yukimu 1.0.0 → 1.1.0

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.
Files changed (62) hide show
  1. package/.cache/replit/env/latest +88 -0
  2. package/.cache/replit/env/latest.json +1 -0
  3. package/.cache/replit/modules/python-3.11.res +1 -0
  4. package/.cache/replit/nix/dotreplitenv.json +1 -1
  5. package/.cache/replit/toolchain.json +1 -1
  6. package/.local/state/workflow-logs/KRgHXizaECjWI5nWtS7Dj/configure_your_app.packager.installForAll.0 +1 -0
  7. package/.local/state/workflow-logs/KRgHXizaECjWI5nWtS7Dj/configure_your_app.shell.exec.1 +1 -0
  8. package/.local/state/workflow-logs/jVavLOnv1MqxUvxhMmqER/configure_your_app.packager.installForAll.0 +1 -0
  9. package/.local/state/workflow-logs/jVavLOnv1MqxUvxhMmqER/configure_your_app.shell.exec.1 +1 -0
  10. package/.replit +4 -1
  11. package/.upm/store.json +1 -1
  12. package/README.md +182 -85
  13. package/package.json +1 -1
  14. package/src/ConnectionPool.ts +133 -0
  15. package/src/Constants.ts +101 -0
  16. package/src/Node.ts +179 -166
  17. package/src/Player.ts +200 -108
  18. package/src/Plugin.ts +23 -0
  19. package/src/Queue.ts +43 -34
  20. package/src/Resolver.ts +29 -77
  21. package/src/Rest.ts +161 -0
  22. package/src/TrackCache.ts +69 -0
  23. package/src/WsQueue.ts +78 -0
  24. package/src/Yukimu.ts +156 -85
  25. package/src/connector/Connector.ts +13 -0
  26. package/src/connector/DiscordJS.ts +33 -0
  27. package/src/connector/Eris.ts +35 -0
  28. package/src/connector/Oceanic.ts +32 -0
  29. package/src/errors/YukimuError.ts +33 -0
  30. package/src/index.ts +22 -0
  31. package/src/plugins/AutoResume.ts +61 -0
  32. package/src/plugins/PlayerMoved.ts +27 -0
  33. package/src/types.ts +49 -82
  34. package/tsconfig.json +3 -1
  35. package/dist/Node.d.ts +0 -32
  36. package/dist/Node.d.ts.map +0 -1
  37. package/dist/Node.js +0 -186
  38. package/dist/Node.js.map +0 -1
  39. package/dist/Player.d.ts +0 -63
  40. package/dist/Player.d.ts.map +0 -1
  41. package/dist/Player.js +0 -205
  42. package/dist/Player.js.map +0 -1
  43. package/dist/Queue.d.ts +0 -29
  44. package/dist/Queue.d.ts.map +0 -1
  45. package/dist/Queue.js +0 -75
  46. package/dist/Queue.js.map +0 -1
  47. package/dist/Resolver.d.ts +0 -30
  48. package/dist/Resolver.d.ts.map +0 -1
  49. package/dist/Resolver.js +0 -121
  50. package/dist/Resolver.js.map +0 -1
  51. package/dist/Yukimu.d.ts +0 -59
  52. package/dist/Yukimu.d.ts.map +0 -1
  53. package/dist/Yukimu.js +0 -135
  54. package/dist/Yukimu.js.map +0 -1
  55. package/dist/index.d.ts +0 -7
  56. package/dist/index.d.ts.map +0 -1
  57. package/dist/index.js +0 -29
  58. package/dist/index.js.map +0 -1
  59. package/dist/types.d.ts +0 -137
  60. package/dist/types.d.ts.map +0 -1
  61. package/dist/types.js +0 -15
  62. package/dist/types.js.map +0 -1
@@ -0,0 +1,88 @@
1
+ declare -gx USER=runner
2
+ declare -gx POETRY_PIP_NO_PREFIX=1
3
+ declare -gx POETRY_CACHE_DIR=/home/runner/workspace/.cache/pypoetry
4
+ declare -gx REPLIT_CLI=/nix/store/cl8kzazapkhlviimpi96dkd083ycp89x-replit-cli-0.0.1/bin/replit
5
+ declare -gx REPLIT_GITSAFE_NEW_REPLS_ENABLED=true
6
+ declare -gx REPLIT_RTLD_LOADER=1
7
+ declare -gx COLORTERM=truecolor
8
+ declare -gx REPLIT_PYTHON_LD_LIBRARY_PATH=/nix/store/pya3p1ihjm446jpqpql93542cirqyn23-cpplibs/lib:/nix/store/c2qsgf2832zi4n29gfkqgkjpvmbmxam6-zlib-1.3.1/lib:/nix/store/f7rcazhd826xlcz43il4vafv28888cgj-glib-2.86.3/lib:/nix/store/ii3ybky5dqjikcrw7vdnh1j76ssy0ycm-libx11-1.8.12/lib:/nix/store/zshby6nalhw4mvap0rr97hv042808c2k-libxext-1.3.6/lib:/nix/store/0r6d7iw0q9wgxxj28zy87n1gjwvk0klp-libxinerama-1.1.5/lib:/nix/store/bb5xxw11ndww7iivcmdpxga9n1da24vg-libxcursor-1.2.3/lib:/nix/store/dyn0y5clf5b556yqwmj4841h43hz75p6-libxrandr-1.5.4/lib:/nix/store/x1f9a0qsj6a1y5nf178naagm2vbxnazc-libxi-1.8.2/lib:/nix/store/pv432a54y6di3n12iqix2dglkswvq1px-libxxf86vm-1.1.6/lib
9
+ declare -gx POETRY_PIP_FROM_PATH=1
10
+ declare -gx NIX_PATH=/home/runner/.nix-defexpr/channels
11
+ declare -gx REPL_SLUG=workspace
12
+ declare -gx GIT_ASKPASS=replit-git-askpass
13
+ declare -gx POETRY_VIRTUALENVS_CREATE=0
14
+ declare -gx CFLAGS=''
15
+ declare -gx REPLIT_CONTAINER=gcr.io/marine-cycle-160323/repl-base:3c526f0870c482ef04b1ca6073a0d578ba34e814
16
+ declare -gx REPLIT_DOMAINS=5880c157-f106-4406-b020-cef4a1c1600e-00-1vwlyfui4qmee.sisko.replit.dev
17
+ declare -gx DATABASE_URL='postgresql://postgres:password@helium/heliumdb?sslmode=disable'
18
+ declare -gx REPLIT_HEIMDALL_ADDR=https://heimdall.replit.com
19
+ declare -gx NIX_CFLAGS_COMPILE=''
20
+ declare -gx LDFLAGS=''
21
+ declare -gx XDG_DATA_DIRS=/nix/store/ynhhsbqi66v2pcy3r8l6g391vpasr3sy-zip-3.0/share:/nix/store/x5hwjkyng8385q1pqhz8wyqkq0izmhpi-replit-runtime-path/share
22
+ declare -gx TZDIR=/etc/zoneinfo
23
+ declare -gx REPLIT_NIX_CHANNEL=legacy
24
+ declare -gx LOCALE_ARCHIVE=/usr/lib/locale/locale-archive
25
+ declare -gx REPL_PUBKEYS='{"crosis-ci":"7YlpcYh82oR9NSTtSYtR5jDL4onNzCGJGq6b+9CuZII=","crosis-ci:1":"7YlpcYh82oR9NSTtSYtR5jDL4onNzCGJGq6b+9CuZII=","crosis-ci:latest":"7YlpcYh82oR9NSTtSYtR5jDL4onNzCGJGq6b+9CuZII=","prod":"tGsjlu/BJvWTgvMaX7acuUb7AO1dXOrRiuk7y083RFE=","prod:1":"tGsjlu/BJvWTgvMaX7acuUb7AO1dXOrRiuk7y083RFE=","prod:3":"9+MCOSHQSQlcodXoot8dC8NLhc862nLkx1/VMsbY2h8=","prod:4":"8uGN+vfszlnV93/HCSHlVLG0xddMlPkir1Ni4JKT4+w=","prod:5":"9+MCOSHQSQlcodXoot8dC8NLhc862nLkx1/VMsbY2h8=","prod:latest":"tGsjlu/BJvWTgvMaX7acuUb7AO1dXOrRiuk7y083RFE=","vault-goval-token":"D5jJoMx1Ml54HM92NLgXl+MzptwDqbSsfyFG6f52g9E=","vault-goval-token:1":"D5jJoMx1Ml54HM92NLgXl+MzptwDqbSsfyFG6f52g9E=","vault-goval-token:latest":"D5jJoMx1Ml54HM92NLgXl+MzptwDqbSsfyFG6f52g9E="}'
26
+ declare -gx REPLIT_CLUSTER=sisko
27
+ declare -gx PGUSER=postgres
28
+ declare -gx POETRY_PIP_NO_ISOLATE=1
29
+ declare -gx LIBGL_DRIVERS_PATH=/nix/store/l4myp7qn0q9bqgmkqq4vnnii22ql1r68-mesa-25.0.7/lib/dri
30
+ declare -gx PGDATABASE=heliumdb
31
+ declare -gx REPLIT_GITSAFE_ENABLED=true
32
+ declare -gx NIX_PS1='\[\033[01;34m\]\w\[\033[00m\]\$ '
33
+ declare -gx UV_PROJECT_ENVIRONMENT=/home/runner/workspace/.pythonlibs
34
+ declare -gx PIP_CONFIG_FILE=/nix/store/z0d7kvaycmw342xmz4xwwybm6p3p0zcs-pip.conf
35
+ declare -gx POETRY_CONFIG_DIR=/nix/store/cyg6h5fbgsfqdimyrc1gflmpx8p0hbkv-poetry-config
36
+ declare -gx PKG_CONFIG_PATH_FOR_TARGET=''
37
+ declare -gx REPLIT_PID1_VERSION=0.0.0-c563c9c
38
+ declare -gx REPLIT_ENVIRONMENT=production
39
+ declare -gx REPLIT_CONNECTORS_HOSTNAME=connectors.replit.com
40
+ declare -gx PGPASSWORD=password
41
+ declare -gx CONNECTORS_HOSTNAME=connectors.replit.com
42
+ declare -gx PROMPT_DIRTRIM=2
43
+ declare -gx POETRY_DOWNLOAD_WITH_CURL=1
44
+ declare -gx REPLIT_LD_AUDIT=/nix/store/sj11ljhx4n79h9g0167f8lg8hp7n545m-replit_rtld_loader-1/rtld_loader.so
45
+ declare -gx REPL_ID=5880c157-f106-4406-b020-cef4a1c1600e
46
+ declare -gx POETRY_INSTALLER_MODERN_INSTALLATION=1
47
+ declare -gx PKG_CONFIG_PATH=''
48
+ declare -gx REPLIT_RIPPKGS_INDICES=/nix/store/cg6q7dm7h9jp20vwj79ahnbsd9cs6iay-rippkgs-indices
49
+ declare -gx REPL_OWNER=babyprank598
50
+ declare -gx PGPORT=5432
51
+ declare -gx npm_config_prefix=/home/runner/workspace/.config/npm/node_global
52
+ declare -gx UV_PYTHON_PREFERENCE=only-system
53
+ declare -gx POETRY_USE_USER_SITE=1
54
+ declare -gx POETRY_PIP_USE_PIP_CACHE=1
55
+ declare -gx REPLIT_SUBCLUSTER=interactive
56
+ declare -gx HOME=/home/runner
57
+ declare -gx REPLIT_EXPO_DEV_DOMAIN=5880c157-f106-4406-b020-cef4a1c1600e-00-1vwlyfui4qmee.expo.sisko.replit.dev
58
+ declare -gx XDG_CACHE_HOME=/home/runner/workspace/.cache
59
+ declare -gx UV_PYTHON_DOWNLOADS=never
60
+ declare -gx DOCKER_CONFIG=/home/runner/workspace/.config/docker
61
+ declare -gx REPLIT_PYTHONPATH=/home/runner/workspace/.pythonlibs/lib/python3.11/site-packages:/nix/store/lxnbcmx15m3yascasf4c9qh7zk19pd2b-python3.11-setuptools-80.9.0/lib/python3.11/site-packages
62
+ declare -gx PYTHONPATH=/nix/store/y50fwh2sha400s38m12psfxpvk2c8w39-sitecustomize/lib/python/site-packages:/nix/store/sqs1z4grvym0nv6r3ksdc990m8sr5wgx-python3.11-pip-25.0.1/lib/python3.11/site-packages
63
+ declare -gx NIXPKGS_ALLOW_UNFREE=1
64
+ declare -gx HOSTNAME=ec1ee4e9aecb
65
+ declare -gx REPLIT_HELIUM_ENABLED=true
66
+ declare -gx NIX_PROFILES='/nix/var/nix/profiles/default /home/runner/.nix-profile'
67
+ declare -gx LANG=en_US.UTF-8
68
+ declare -gx __EGL_VENDOR_LIBRARY_FILENAMES=/nix/store/l4myp7qn0q9bqgmkqq4vnnii22ql1r68-mesa-25.0.7/share/glvnd/egl_vendor.d/50_mesa.json
69
+ declare -gx XDG_CONFIG_HOME=/home/runner/workspace/.config
70
+ declare -gx GIT_EDITOR=replit-git-editor
71
+ declare -gx PGHOST=helium
72
+ declare -gx REPL_OWNER_ID=37551296
73
+ declare -gx DISPLAY=:0
74
+ declare -gx REPLIT_GITSAFE_EXISTING_REPLS_ENABLED=true
75
+ declare -gx REPLIT_DEV_DOMAIN=5880c157-f106-4406-b020-cef4a1c1600e-00-1vwlyfui4qmee.sisko.replit.dev
76
+ declare -gx REPL_HOME=/home/runner/workspace
77
+ declare -gx REPL_LANGUAGE=nix
78
+ declare -gx PYTHONUSERBASE=/home/runner/workspace/.pythonlibs
79
+ declare -gx GI_TYPELIB_PATH=''
80
+ declare -gx REPLIT_ARTIFACT_ROUTER=/nix/store/ihkw29ncs845z7cwcvw5xr8k2bf12c1l-artifact-router-0.1.0/bin/artifact-router
81
+ declare -gx REPLIT_BASHRC=/nix/store/lsgsb0ar7rdwa09d1z2dnfjh4188pddk-replit-bashrc/bashrc
82
+ declare -gx XDG_DATA_HOME=/home/runner/workspace/.local/share
83
+ declare -gx NIX_LDFLAGS=''
84
+ read -r _new_path <<< "/nix/store/ynhhsbqi66v2pcy3r8l6g391vpasr3sy-zip-3.0/bin:/home/runner/workspace/.pythonlibs/bin:/nix/store/flbj8bq2vznkcwss7sm0ky8rd0k6kar7-python-wrapped-0.1.0/bin:/nix/store/xwg0ddq9mjf6ibwdvp93jsp0cf51z3xr-pip-wrapper/bin:/nix/store/ypy3l3k428kc1kmcw090wlbxi8vj1m8l-poetry-wrapper/bin:/nix/store/6m2322jq0rkfdnv6cm3dq8437djbfv1l-uv-0.9.5/bin:/nix/store/b1kq183rmmiv453fn6f8bfmi1drxvxba-npx/bin:/home/runner/workspace/.config/npm/node_global/bin:/home/runner/workspace/node_modules/.bin:/nix/store/1lagpgadaybvs1n2312gysg2phjk89y8-nodejs-20.20.0-wrapped/bin:/nix/store/1xk3mgscq548ypyrgm2n5kwdii92w9ql-bun-1.3.6/bin:/nix/store/61lr9izijvg30pcribjdxgjxvh3bysp4-pnpm-10.26.1/bin:/nix/store/23078nfww258q1vjxbmyak0svvxcvj4s-yarn-1.22.22/bin:/nix/store/8sa75mbvbn3kxicggyyjggmkigvzddks-prettier-3.6.2/bin:/nix/store/ph3jll6y6jyclpmxg96y98b3gqhj54kv-pid1/bin:/nix/store/x5hwjkyng8385q1pqhz8wyqkq0izmhpi-replit-runtime-path/bin:/home/runner/.nix-profile/bin:/home/runner/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
85
+ #PATH=/nix/store/ynhhsbqi66v2pcy3r8l6g391vpasr3sy-zip-3.0/bin:/home/runner/workspace/.pythonlibs/bin:/nix/store/flbj8bq2vznkcwss7sm0ky8rd0k6kar7-python-wrapped-0.1.0/bin:/nix/store/xwg0ddq9mjf6ibwdvp93jsp0cf51z3xr-pip-wrapper/bin:/nix/store/ypy3l3k428kc1kmcw090wlbxi8vj1m8l-poetry-wrapper/bin:/nix/store/6m2322jq0rkfdnv6cm3dq8437djbfv1l-uv-0.9.5/bin:/nix/store/b1kq183rmmiv453fn6f8bfmi1drxvxba-npx/bin:/home/runner/workspace/.config/npm/node_global/bin:/home/runner/workspace/node_modules/.bin:/nix/store/1lagpgadaybvs1n2312gysg2phjk89y8-nodejs-20.20.0-wrapped/bin:/nix/store/1xk3mgscq548ypyrgm2n5kwdii92w9ql-bun-1.3.6/bin:/nix/store/61lr9izijvg30pcribjdxgjxvh3bysp4-pnpm-10.26.1/bin:/nix/store/23078nfww258q1vjxbmyak0svvxcvj4s-yarn-1.22.22/bin:/nix/store/8sa75mbvbn3kxicggyyjggmkigvzddks-prettier-3.6.2/bin:/nix/store/ph3jll6y6jyclpmxg96y98b3gqhj54kv-pid1/bin:/nix/store/x5hwjkyng8385q1pqhz8wyqkq0izmhpi-replit-runtime-path/bin:/home/runner/.nix-profile/bin:/home/runner/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
86
+ if [ -e "/run/replit/env/last" ]; then read -r _last_path < <(\grep '^#PATH=' /run/replit/env/last | cut -f 2 -d =); fi
87
+ _user_components="$(\tr : $'\n' <<< "${PATH:-}" |\grep -xv -f <(\tr : $'\n' <<< "${_last_path}") |\tr $'\n' :)"
88
+ declare -gx PATH="${_user_components}${_new_path}"
@@ -0,0 +1 @@
1
+ {"environment":{"CFLAGS":"","COLORTERM":"truecolor","CONNECTORS_HOSTNAME":"connectors.replit.com","DATABASE_URL":"postgresql://postgres:password@helium/heliumdb?sslmode=disable","DISPLAY":":0","DOCKER_CONFIG":"/home/runner/workspace/.config/docker","GIT_ASKPASS":"replit-git-askpass","GIT_EDITOR":"replit-git-editor","GI_TYPELIB_PATH":"","HOME":"/home/runner","HOSTNAME":"ec1ee4e9aecb","LANG":"en_US.UTF-8","LDFLAGS":"","LIBGL_DRIVERS_PATH":"/nix/store/l4myp7qn0q9bqgmkqq4vnnii22ql1r68-mesa-25.0.7/lib/dri","LOCALE_ARCHIVE":"/usr/lib/locale/locale-archive","NIXPKGS_ALLOW_UNFREE":"1","NIX_CFLAGS_COMPILE":"","NIX_LDFLAGS":"","NIX_PATH":"/home/runner/.nix-defexpr/channels","NIX_PROFILES":"/nix/var/nix/profiles/default /home/runner/.nix-profile","NIX_PS1":"\\[\\033[01;34m\\]\\w\\[\\033[00m\\]\\$ ","PATH":"/nix/store/ynhhsbqi66v2pcy3r8l6g391vpasr3sy-zip-3.0/bin:/home/runner/workspace/.pythonlibs/bin:/nix/store/flbj8bq2vznkcwss7sm0ky8rd0k6kar7-python-wrapped-0.1.0/bin:/nix/store/xwg0ddq9mjf6ibwdvp93jsp0cf51z3xr-pip-wrapper/bin:/nix/store/ypy3l3k428kc1kmcw090wlbxi8vj1m8l-poetry-wrapper/bin:/nix/store/6m2322jq0rkfdnv6cm3dq8437djbfv1l-uv-0.9.5/bin:/nix/store/b1kq183rmmiv453fn6f8bfmi1drxvxba-npx/bin:/home/runner/workspace/.config/npm/node_global/bin:/home/runner/workspace/node_modules/.bin:/nix/store/1lagpgadaybvs1n2312gysg2phjk89y8-nodejs-20.20.0-wrapped/bin:/nix/store/1xk3mgscq548ypyrgm2n5kwdii92w9ql-bun-1.3.6/bin:/nix/store/61lr9izijvg30pcribjdxgjxvh3bysp4-pnpm-10.26.1/bin:/nix/store/23078nfww258q1vjxbmyak0svvxcvj4s-yarn-1.22.22/bin:/nix/store/8sa75mbvbn3kxicggyyjggmkigvzddks-prettier-3.6.2/bin:/nix/store/ph3jll6y6jyclpmxg96y98b3gqhj54kv-pid1/bin:/nix/store/x5hwjkyng8385q1pqhz8wyqkq0izmhpi-replit-runtime-path/bin:/home/runner/.nix-profile/bin:/home/runner/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin","PGDATABASE":"heliumdb","PGHOST":"helium","PGPASSWORD":"password","PGPORT":"5432","PGUSER":"postgres","PIP_CONFIG_FILE":"/nix/store/z0d7kvaycmw342xmz4xwwybm6p3p0zcs-pip.conf","PKG_CONFIG_PATH":"","PKG_CONFIG_PATH_FOR_TARGET":"","POETRY_CACHE_DIR":"/home/runner/workspace/.cache/pypoetry","POETRY_CONFIG_DIR":"/nix/store/cyg6h5fbgsfqdimyrc1gflmpx8p0hbkv-poetry-config","POETRY_DOWNLOAD_WITH_CURL":"1","POETRY_INSTALLER_MODERN_INSTALLATION":"1","POETRY_PIP_FROM_PATH":"1","POETRY_PIP_NO_ISOLATE":"1","POETRY_PIP_NO_PREFIX":"1","POETRY_PIP_USE_PIP_CACHE":"1","POETRY_USE_USER_SITE":"1","POETRY_VIRTUALENVS_CREATE":"0","PROMPT_DIRTRIM":"2","PYTHONPATH":"/nix/store/y50fwh2sha400s38m12psfxpvk2c8w39-sitecustomize/lib/python/site-packages:/nix/store/sqs1z4grvym0nv6r3ksdc990m8sr5wgx-python3.11-pip-25.0.1/lib/python3.11/site-packages","PYTHONUSERBASE":"/home/runner/workspace/.pythonlibs","REPLIT_ARTIFACT_ROUTER":"/nix/store/ihkw29ncs845z7cwcvw5xr8k2bf12c1l-artifact-router-0.1.0/bin/artifact-router","REPLIT_BASHRC":"/nix/store/lsgsb0ar7rdwa09d1z2dnfjh4188pddk-replit-bashrc/bashrc","REPLIT_CLI":"/nix/store/cl8kzazapkhlviimpi96dkd083ycp89x-replit-cli-0.0.1/bin/replit","REPLIT_CLUSTER":"sisko","REPLIT_CONNECTORS_HOSTNAME":"connectors.replit.com","REPLIT_CONTAINER":"gcr.io/marine-cycle-160323/repl-base:3c526f0870c482ef04b1ca6073a0d578ba34e814","REPLIT_DEV_DOMAIN":"5880c157-f106-4406-b020-cef4a1c1600e-00-1vwlyfui4qmee.sisko.replit.dev","REPLIT_DOMAINS":"5880c157-f106-4406-b020-cef4a1c1600e-00-1vwlyfui4qmee.sisko.replit.dev","REPLIT_ENVIRONMENT":"production","REPLIT_EXPO_DEV_DOMAIN":"5880c157-f106-4406-b020-cef4a1c1600e-00-1vwlyfui4qmee.expo.sisko.replit.dev","REPLIT_GITSAFE_ENABLED":"true","REPLIT_GITSAFE_EXISTING_REPLS_ENABLED":"true","REPLIT_GITSAFE_NEW_REPLS_ENABLED":"true","REPLIT_HEIMDALL_ADDR":"https://heimdall.replit.com","REPLIT_HELIUM_ENABLED":"true","REPLIT_LD_AUDIT":"/nix/store/sj11ljhx4n79h9g0167f8lg8hp7n545m-replit_rtld_loader-1/rtld_loader.so","REPLIT_NIX_CHANNEL":"legacy","REPLIT_PID1_VERSION":"0.0.0-c563c9c","REPLIT_PYTHONPATH":"/home/runner/workspace/.pythonlibs/lib/python3.11/site-packages:/nix/store/lxnbcmx15m3yascasf4c9qh7zk19pd2b-python3.11-setuptools-80.9.0/lib/python3.11/site-packages","REPLIT_PYTHON_LD_LIBRARY_PATH":"/nix/store/pya3p1ihjm446jpqpql93542cirqyn23-cpplibs/lib:/nix/store/c2qsgf2832zi4n29gfkqgkjpvmbmxam6-zlib-1.3.1/lib:/nix/store/f7rcazhd826xlcz43il4vafv28888cgj-glib-2.86.3/lib:/nix/store/ii3ybky5dqjikcrw7vdnh1j76ssy0ycm-libx11-1.8.12/lib:/nix/store/zshby6nalhw4mvap0rr97hv042808c2k-libxext-1.3.6/lib:/nix/store/0r6d7iw0q9wgxxj28zy87n1gjwvk0klp-libxinerama-1.1.5/lib:/nix/store/bb5xxw11ndww7iivcmdpxga9n1da24vg-libxcursor-1.2.3/lib:/nix/store/dyn0y5clf5b556yqwmj4841h43hz75p6-libxrandr-1.5.4/lib:/nix/store/x1f9a0qsj6a1y5nf178naagm2vbxnazc-libxi-1.8.2/lib:/nix/store/pv432a54y6di3n12iqix2dglkswvq1px-libxxf86vm-1.1.6/lib","REPLIT_RIPPKGS_INDICES":"/nix/store/cg6q7dm7h9jp20vwj79ahnbsd9cs6iay-rippkgs-indices","REPLIT_RTLD_LOADER":"1","REPLIT_SUBCLUSTER":"interactive","REPL_HOME":"/home/runner/workspace","REPL_ID":"5880c157-f106-4406-b020-cef4a1c1600e","REPL_LANGUAGE":"nix","REPL_OWNER":"babyprank598","REPL_OWNER_ID":"37551296","REPL_PUBKEYS":"{\"crosis-ci\":\"7YlpcYh82oR9NSTtSYtR5jDL4onNzCGJGq6b+9CuZII=\",\"crosis-ci:1\":\"7YlpcYh82oR9NSTtSYtR5jDL4onNzCGJGq6b+9CuZII=\",\"crosis-ci:latest\":\"7YlpcYh82oR9NSTtSYtR5jDL4onNzCGJGq6b+9CuZII=\",\"prod\":\"tGsjlu/BJvWTgvMaX7acuUb7AO1dXOrRiuk7y083RFE=\",\"prod:1\":\"tGsjlu/BJvWTgvMaX7acuUb7AO1dXOrRiuk7y083RFE=\",\"prod:3\":\"9+MCOSHQSQlcodXoot8dC8NLhc862nLkx1/VMsbY2h8=\",\"prod:4\":\"8uGN+vfszlnV93/HCSHlVLG0xddMlPkir1Ni4JKT4+w=\",\"prod:5\":\"9+MCOSHQSQlcodXoot8dC8NLhc862nLkx1/VMsbY2h8=\",\"prod:latest\":\"tGsjlu/BJvWTgvMaX7acuUb7AO1dXOrRiuk7y083RFE=\",\"vault-goval-token\":\"D5jJoMx1Ml54HM92NLgXl+MzptwDqbSsfyFG6f52g9E=\",\"vault-goval-token:1\":\"D5jJoMx1Ml54HM92NLgXl+MzptwDqbSsfyFG6f52g9E=\",\"vault-goval-token:latest\":\"D5jJoMx1Ml54HM92NLgXl+MzptwDqbSsfyFG6f52g9E=\"}","REPL_SLUG":"workspace","TZDIR":"/etc/zoneinfo","USER":"runner","UV_PROJECT_ENVIRONMENT":"/home/runner/workspace/.pythonlibs","UV_PYTHON_DOWNLOADS":"never","UV_PYTHON_PREFERENCE":"only-system","XDG_CACHE_HOME":"/home/runner/workspace/.cache","XDG_CONFIG_HOME":"/home/runner/workspace/.config","XDG_DATA_DIRS":"/nix/store/ynhhsbqi66v2pcy3r8l6g391vpasr3sy-zip-3.0/share:/nix/store/x5hwjkyng8385q1pqhz8wyqkq0izmhpi-replit-runtime-path/share","XDG_DATA_HOME":"/home/runner/workspace/.local/share","__EGL_VENDOR_LIBRARY_FILENAMES":"/nix/store/l4myp7qn0q9bqgmkqq4vnnii22ql1r68-mesa-25.0.7/share/glvnd/egl_vendor.d/50_mesa.json","npm_config_prefix":"/home/runner/workspace/.config/npm/node_global"}}
@@ -0,0 +1 @@
1
+ {"type":"resolve","resolvedModuleId":"python-3.11","inputHash":"","resolutionPath":["python-3.11"],"error":"","Changed":true}
@@ -1 +1 @@
1
- {"channel":"","channel_nix_path":"/nix/store/42iv6n6l2izliq7lhy3gsaqsycj6np1h-nixpkgs/nixpkgs","env":null,"packages":null}
1
+ {"channel":"","channel_nix_path":"/nix/store/42iv6n6l2izliq7lhy3gsaqsycj6np1h-nixpkgs/nixpkgs","env":{"CFLAGS":"","GI_TYPELIB_PATH":"","LDFLAGS":"","NIX_CFLAGS_COMPILE":"","NIX_LDFLAGS":"","PATH":"/nix/store/ynhhsbqi66v2pcy3r8l6g391vpasr3sy-zip-3.0/bin","PKG_CONFIG_PATH":"","PKG_CONFIG_PATH_FOR_TARGET":"","REPLIT_LD_LIBRARY_PATH":"","XDG_DATA_DIRS":"/nix/store/ynhhsbqi66v2pcy3r8l6g391vpasr3sy-zip-3.0/share"},"packages":["zip"]}
@@ -1 +1 @@
1
- {"runs":[{"id":"module:nodejs-20/runner:nodeJS", "name":"Node.js", "fileParam":true, "language":"javascript", "fileTypeAttrs":{}, "displayVersion":"20.20.0", "run":{"command":{"args":["sh", "-c", "/nix/store/1lagpgadaybvs1n2312gysg2phjk89y8-nodejs-20.20.0-wrapped/bin/node $file"]}}, "defaultEntrypoints":["index.js", "main.js"]}], "languageServers":[{"id":"module:nodejs-20/languageServer:typescript-language-server", "name":"TypeScript Language Server", "language":"javascript", "fileTypeAttrs":{"extensions":[".js", ".jsx", ".ts", ".tsx", ".mjs", ".mts", ".cjs", ".cts", ".es6", ".json"]}, "config":{"startCommand":{"args":["sh", "-c", "/nix/store/pkx0287w1vx971gahfkggqa59v35d4bm-typescript-language-server-5.1.3/bin/typescript-language-server --stdio"]}, "initializationOptionsJson":"{\"disableAutomaticTypingAcquisition\":true,\"maxTsServerMemory\":1536,\"tsserver\":{\"fallbackPath\":\"/nix/store/6wjhsy7rpyxbpl65grd5a8aq96b50i8a-typescript-5.9.3/lib/node_modules/typescript/lib\"}}"}, "displayVersion":"5.1.3"}, {"id":"module:replit/languageServer:dotreplit-lsp", "name":".replit LSP", "language":"dotreplit", "fileTypeAttrs":{}, "config":{"startCommand":{"args":["sh", "-c", "/nix/store/qq4mijbp008lc0r1h42jy3fhwakqz6nf-taplo-0.patched/bin/taplo lsp -c /nix/store/7nplpw32gfk08i6d1v3wmwj3b1qd0apw-taplo-config.toml stdio"]}}}], "packagers":[{"id":"module:nodejs-20/packager:upmNodejs", "name":"Node.js packager (npm, yarn, pnpm, bun)", "language":"nodejs", "packageSearch":true, "guessImports":true}], "formatters":[{"id":"module:nodejs-20/formatter:prettier", "name":"Prettier", "startCommand":{"args":["/nix/store/h0yq53vj17w8bqs8bdldg2kg1llkqi7i-run-prettier/bin/run-prettier"], "lifecycle":"STDIN", "splitStderr":true}, "fileTypeAttrs":{"extensions":[".js", ".jsx", ".ts", ".tsx", ".json", ".html"]}, "displayVersion":"3.6.2", "supportsRangeFormatting":true}, {"id":"module:nodejs-20/languageServer:typescript-language-server", "name":"TypeScript Language Server", "fileTypeAttrs":{"extensions":[".js", ".jsx", ".ts", ".tsx", ".mjs", ".mts", ".cjs", ".cts", ".es6", ".json"]}, "displayVersion":"5.1.3"}, {"id":"module:replit/languageServer:dotreplit-lsp", "name":".replit LSP", "fileTypeAttrs":{}}]}
1
+ {"runs":[{"id":"module:nodejs-20/runner:nodeJS", "name":"Node.js", "fileParam":true, "language":"javascript", "fileTypeAttrs":{}, "displayVersion":"20.20.0", "run":{"command":{"args":["sh", "-c", "/nix/store/1lagpgadaybvs1n2312gysg2phjk89y8-nodejs-20.20.0-wrapped/bin/node $file"]}}, "defaultEntrypoints":["index.js", "main.js"]}, {"id":"module:python-3.11/runner:python", "name":"Python 3.11", "fileParam":true, "language":"python3", "fileTypeAttrs":{}, "displayVersion":"3.11.14", "run":{"command":{"args":["sh", "-c", "/nix/store/s4ckxp77ljlikarkka88ba7qr5mlka97-python3-wrapper/bin/python3 $file"]}}, "defaultEntrypoints":["main.py", "app.py", "run.py"]}], "languageServers":[{"id":"module:nodejs-20/languageServer:typescript-language-server", "name":"TypeScript Language Server", "language":"javascript", "fileTypeAttrs":{"extensions":[".js", ".jsx", ".ts", ".tsx", ".mjs", ".mts", ".cjs", ".cts", ".es6", ".json"]}, "config":{"startCommand":{"args":["sh", "-c", "/nix/store/pkx0287w1vx971gahfkggqa59v35d4bm-typescript-language-server-5.1.3/bin/typescript-language-server --stdio"]}, "initializationOptionsJson":"{\"disableAutomaticTypingAcquisition\":true,\"maxTsServerMemory\":1536,\"tsserver\":{\"fallbackPath\":\"/nix/store/6wjhsy7rpyxbpl65grd5a8aq96b50i8a-typescript-5.9.3/lib/node_modules/typescript/lib\"}}"}, "displayVersion":"5.1.3"}, {"id":"module:python-3.11/languageServer:ty", "name":"ty", "language":"python3", "fileTypeAttrs":{}, "config":{"startCommand":{"args":["sh", "-c", "/nix/store/775cppcslcvxd4x2v8x4k78xw94zg88a-ty-0.0.21/bin/ty server"]}}, "displayVersion":"0.0.21"}, {"id":"module:replit/languageServer:dotreplit-lsp", "name":".replit LSP", "language":"dotreplit", "fileTypeAttrs":{}, "config":{"startCommand":{"args":["sh", "-c", "/nix/store/qq4mijbp008lc0r1h42jy3fhwakqz6nf-taplo-0.patched/bin/taplo lsp -c /nix/store/7nplpw32gfk08i6d1v3wmwj3b1qd0apw-taplo-config.toml stdio"]}}}], "packagers":[{"id":"module:python-3.11/packager:upmPython", "name":"Python packager", "language":"python3", "packageSearch":true, "guessImports":true}, {"id":"module:nodejs-20/packager:upmNodejs", "name":"Node.js packager (npm, yarn, pnpm, bun)", "language":"nodejs", "packageSearch":true, "guessImports":true}], "formatters":[{"id":"module:nodejs-20/formatter:prettier", "name":"Prettier", "startCommand":{"args":["/nix/store/h0yq53vj17w8bqs8bdldg2kg1llkqi7i-run-prettier/bin/run-prettier"], "lifecycle":"STDIN", "splitStderr":true}, "fileTypeAttrs":{"extensions":[".js", ".jsx", ".ts", ".tsx", ".json", ".html"]}, "displayVersion":"3.6.2", "supportsRangeFormatting":true}, {"id":"module:nodejs-20/languageServer:typescript-language-server", "name":"TypeScript Language Server", "fileTypeAttrs":{"extensions":[".js", ".jsx", ".ts", ".tsx", ".mjs", ".mts", ".cjs", ".cts", ".es6", ".json"]}, "displayVersion":"5.1.3"}, {"id":"module:python-3.11/formatter:ruff", "name":"Ruff", "startCommand":{"args":["/nix/store/mqvkfmbcri2jllqsjmqcgr353i4j6k7r-run-ruff-format/bin/run-ruff-format"], "lifecycle":"STDIN", "splitStderr":true}, "fileTypeAttrs":{"extensions":[".py"]}, "displayVersion":"0.14.11"}, {"id":"module:python-3.11/languageServer:ty", "name":"ty", "fileTypeAttrs":{}, "displayVersion":"0.0.21"}, {"id":"module:replit/languageServer:dotreplit-lsp", "name":".replit LSP", "fileTypeAttrs":{}}]}
@@ -0,0 +1 @@
1
+ Please use the Workflows pane to configure your app. For more info, see: https://docs.replit.com/replit-workspace/workflows#creating-workflows
@@ -0,0 +1 @@
1
+ Please use the Workflows pane to configure your app. For more info, see: https://docs.replit.com/replit-workspace/workflows#creating-workflows
package/.replit CHANGED
@@ -1,4 +1,7 @@
1
- modules = ["nodejs-20"]
1
+ modules = ["nodejs-20", "python-3.11"]
2
2
 
3
3
  [agent]
4
4
  expertMode = true
5
+
6
+ [nix]
7
+ packages = ["zip"]
package/.upm/store.json CHANGED
@@ -1 +1 @@
1
- {"version":2,"languages":{"nodejs-npm":{"specfileHash":"305f2ee63ccbb188aa67eb515c9baf60","lockfileHash":"993e663e31dc86082c38db12d1e2c218"}}}
1
+ {"version":2,"languages":{"nodejs-npm":{},"python3-uv":{}}}
package/README.md CHANGED
@@ -1,144 +1,227 @@
1
1
  # Yukimu 🎵
2
2
 
3
- A powerful **Lavalink v4** wrapper for Discord bots — built like Shoukaku.
3
+ A **Shoukaku-level** Lavalink v3/v4 wrapper for Discord bots.
4
4
 
5
5
  Supports: YouTube · YouTube Music · Spotify · Deezer · Apple Music · JioSaavn · Tidal · SoundCloud · Yandex Music
6
6
 
7
7
  ---
8
8
 
9
- ## Requirements
10
-
11
- - Node.js 18+
12
- - A running **Lavalink v4** server
13
- - **LavaSrc plugin** on your Lavalink server (for Spotify, Deezer, Apple Music, Tidal, JioSaavn)
14
-
15
9
  ## Install
16
10
 
17
11
  ```bash
18
12
  npm install yukimu ws
19
- npm install -D typescript @types/node @types/ws
20
13
  ```
21
14
 
22
- ## Lavalink Setup
23
-
24
- Your `application.yml` needs the LavaSrc plugin for multi-source support:
25
-
26
- ```yaml
27
- lavalink:
28
- plugins:
29
- - dependency: "com.github.topi314.lavasrc:lavasrc-plugin:4.3.0"
30
- repository: "https://maven.topi.wtf/releases"
31
-
32
- plugins:
33
- lavasrc:
34
- providers:
35
- - "ytsearch:\"%ISRC%\""
36
- - "ytsearch:%QUERY%"
37
- sources:
38
- spotify: true
39
- appleMusic: true
40
- deezer: true
41
- yandexMusic: true
42
- jiosaavn: true
43
- spotify:
44
- clientId: "YOUR_SPOTIFY_CLIENT_ID"
45
- clientSecret: "YOUR_SPOTIFY_CLIENT_SECRET"
46
- appleMusic:
47
- mediaAPIToken: "YOUR_APPLE_MUSIC_TOKEN"
48
- deezer:
49
- masterDecryptionKey: "YOUR_DEEZER_KEY"
50
- ```
15
+ ---
51
16
 
52
17
  ## Quick Start
53
18
 
54
19
  ```ts
55
- import { Client, GatewayIntentBits } from "discord.js";
56
- import { Yukimu } from "yukimu";
57
-
58
- const client = new Client({ intents: [...] });
59
-
60
- const yukimu = new Yukimu({
61
- clientId: "BOT_ID",
62
- token: "BOT_TOKEN",
63
- nodes: [{
64
- name: "main",
65
- host: "localhost",
66
- port: 2333,
67
- password: "youshallnotpass",
68
- }],
69
- defaultSource: "youtube",
70
- });
20
+ import { Yukimu, DiscordJS } from "yukimu";
21
+
22
+ const yukimu = new Yukimu(
23
+ {
24
+ clientId: "BOT_CLIENT_ID",
25
+ defaultSource: "youtube",
26
+ spotify: { clientId: "...", clientSecret: "..." },
27
+ },
28
+ new DiscordJS(client), // connector — handles voice events automatically
29
+ [
30
+ {
31
+ name: "main",
32
+ host: "localhost",
33
+ port: 2333,
34
+ password: "youshallnotpass",
35
+ version: 4, // 3 or 4
36
+ resumeKey: "yukimu",
37
+ resumeTimeout: 60,
38
+ retries: 5,
39
+ }
40
+ ]
41
+ );
42
+ ```
71
43
 
72
- // Required: forward voice payloads
73
- yukimu.sendPayload = (guildId, payload) => {
74
- client.guilds.cache.get(guildId)?.shard.send(payload);
75
- };
44
+ ---
76
45
 
77
- // Required: forward voice events
78
- client.on("raw", (packet) => {
79
- if (packet.t === "VOICE_STATE_UPDATE") yukimu.handleVoiceStateUpdate(packet.d);
80
- if (packet.t === "VOICE_SERVER_UPDATE") yukimu.handleVoiceServerUpdate(packet.d);
81
- });
46
+ ## Connectors
47
+
48
+ Yukimu uses a connector system like Shoukaku — works with any Discord library.
49
+
50
+ ```ts
51
+ // Discord.js
52
+ new DiscordJS(client)
53
+
54
+ // Custom connector — extend Connector base class
55
+ class MyConnector extends Connector {
56
+ listen() { /* attach voice events */ }
57
+ sendPayload(guildId, payload) { /* send to shard */ }
58
+ }
82
59
  ```
83
60
 
84
- ## Search Examples
61
+ ---
62
+
63
+ ## Search
85
64
 
86
65
  ```ts
87
66
  // Search YouTube (default)
88
- const result = await yukimu.search("never gonna give you up");
67
+ const result = await yukimu.search("Never Gonna Give You Up");
89
68
 
90
69
  // Search Spotify
91
- const result = await yukimu.search("blinding lights", "spotify");
70
+ const result = await yukimu.search("Blinding Lights", { source: "spotify" });
92
71
 
93
72
  // Direct URL (any platform)
94
73
  const result = await yukimu.search("https://open.spotify.com/track/...");
95
74
  const result = await yukimu.search("https://www.jiosaavn.com/song/...");
96
75
  const result = await yukimu.search("https://tidal.com/browse/track/...");
76
+
77
+ // With requester
78
+ const result = await yukimu.search("query", { requester: message.author });
97
79
  ```
98
80
 
81
+ ---
82
+
99
83
  ## Player API
100
84
 
101
85
  ```ts
102
86
  const player = yukimu.createPlayer({
103
87
  guildId: "123",
104
88
  voiceChannelId: "456",
89
+ textChannelId: "789",
105
90
  selfDeaf: true,
106
91
  volume: 80,
107
92
  });
108
93
 
109
- await player.add(track); // Add & auto-play
110
- await player.pause(); // Pause
111
- await player.resume(); // Resume
112
- await player.skip(); // Skip
113
- await player.seek(30000); // Seek to 30s
114
- await player.setVolume(80); // Volume 0-1000
115
- await player.setBassBoost("high"); // Bass boost
116
- await player.setNightcore(true); // Nightcore
117
- await player.set8D(true); // 8D audio
118
- await player.clearFilters(); // Clear all filters
119
- player.queue.shuffle(); // Shuffle queue
120
- player.setLoop("track"); // Loop: none | track | queue
121
- yukimu.destroyPlayer(guildId); // Disconnect
94
+ // Playback
95
+ await player.add(track, requester); // Add track & auto-play
96
+ await player.add(tracks, requester); // Add array of tracks
97
+ await player.play(track); // Play specific track
98
+ await player.pause(); // Pause
99
+ await player.resume(); // Resume
100
+ await player.skip(); // Skip to next
101
+ await player.stop(); // Stop
102
+ await player.seek(30000); // Seek to 30s
103
+ await player.setVolume(80); // Volume 0-1000
104
+ await player.move("channelId"); // Move voice channel
105
+ await player.moveToNode(node); // Move to different Lavalink node
106
+ yukimu.destroyPlayer(guildId); // Disconnect & destroy
107
+
108
+ // Queue
109
+ player.queue.add(track); // Add to queue
110
+ player.queue.remove(0); // Remove at index
111
+ player.queue.move(0, 2); // Reorder
112
+ player.queue.shuffle(); // Shuffle
113
+ player.queue.skipto(3); // Skip to position
114
+ player.queue.clear(); // Clear queue
115
+ player.queue.peek(10); // See upcoming tracks
116
+ player.queue.size; // Queue length
117
+ player.queue.totalDuration; // Total duration in ms
118
+ player.queue.previous; // Last 10 played tracks
119
+
120
+ // Loop
121
+ player.setLoop("none"); // No loop
122
+ player.setLoop("track"); // Loop current track
123
+ player.setLoop("queue"); // Loop entire queue
124
+
125
+ // Player data store (like Kazagumo)
126
+ player.data.set("247", true);
127
+ player.data.get("247");
128
+
129
+ // Real-time position
130
+ player.realPosition; // Estimated current position in ms
131
+ ```
132
+
133
+ ---
134
+
135
+ ## Filters
136
+
137
+ ```ts
138
+ // Presets
139
+ await player.setBassBoost("off" | "low" | "medium" | "high" | "extreme");
140
+ await player.setNightcore(true);
141
+ await player.setVaporwave(true);
142
+ await player.set8D(true);
143
+ await player.setKaraoke(true);
144
+ await player.setTremolo(true);
145
+ await player.setVibrato(true);
146
+ await player.setLowPass(true);
147
+ await player.clearFilters();
148
+
149
+ // Custom filters
150
+ await player.setFilters({
151
+ equalizer: [{ band: 0, gain: 0.5 }],
152
+ timescale: { speed: 1.0, pitch: 1.0, rate: 1.0 },
153
+ rotation: { rotationHz: 0.2 },
154
+ distortion: { sinOffset: 0, sinScale: 1 },
155
+ channelMix: { leftToLeft: 1, rightToRight: 1 },
156
+ lowPass: { smoothing: 20 },
157
+ karaoke: { level: 1, monoLevel: 1, filterBand: 220, filterWidth: 100 },
158
+ tremolo: { frequency: 2, depth: 0.5 },
159
+ vibrato: { frequency: 2, depth: 0.5 },
160
+ });
122
161
  ```
123
162
 
163
+ ---
164
+
124
165
  ## Events
125
166
 
126
167
  ```ts
168
+ yukimu.on("nodeConnecting", (node) => {});
169
+ yukimu.on("nodeConnect", (node) => {});
127
170
  yukimu.on("nodeReady", (node) => {});
171
+ yukimu.on("nodeDisconnect", (node, code, reason) => {});
172
+ yukimu.on("nodeError", (node, error) => {});
173
+
128
174
  yukimu.on("trackStart", (player, track) => {});
129
175
  yukimu.on("trackEnd", (player, track, reason) => {});
130
176
  yukimu.on("trackError", (player, track, exception) => {});
177
+ yukimu.on("trackStuck", (player, track, threshold) => {});
178
+
179
+ yukimu.on("playerCreate", (player) => {});
180
+ yukimu.on("playerDestroy", (player) => {});
181
+ yukimu.on("playerUpdate", (player) => {});
182
+ yukimu.on("playerMove", (player, oldChannel, newChannel) => {});
131
183
  yukimu.on("queueEnd", (player) => {});
132
- yukimu.on("nodeDisconnect", (node, code, reason) => {});
184
+ yukimu.on("socketClosed", (player, code, reason, byRemote) => {});
133
185
  ```
134
186
 
187
+ ---
188
+
189
+ ## Node Management
190
+
191
+ ```ts
192
+ // Add/remove nodes at runtime
193
+ yukimu.addNode({ name: "new", host: "...", port: 2333, password: "...", version: 4 });
194
+ yukimu.removeNode("old");
195
+
196
+ // Get best node
197
+ const node = yukimu.getBestNode(); // lowest penalty
198
+ const node = yukimu.getNode("main"); // by name
199
+
200
+ // Custom node resolver (like Shoukaku)
201
+ yukimu.nodeResolver = (nodes) => {
202
+ return [...nodes.values()]
203
+ .filter(n => n.connected)
204
+ .sort((a, b) => a.penalties - b.penalties)
205
+ .shift();
206
+ };
207
+
208
+ // Node info
209
+ node.info; // sourceManagers, filters, plugins, version
210
+ node.stats; // players, cpu, memory, frameStats
211
+ node.penalties; // load balancing score
212
+ node.version; // 3 or 4
213
+ node.resumed; // whether session was resumed
214
+ ```
215
+
216
+ ---
217
+
135
218
  ## Supported Sources
136
219
 
137
- | Source | Search | Direct URL | Requires |
138
- |--------|--------|------------|---------|
139
- | YouTube | ✅ | ✅ | Lavalink default |
140
- | YouTube Music | ✅ | ✅ | Lavalink default |
141
- | SoundCloud | ✅ | ✅ | Lavalink default |
220
+ | Source | Search | URL | Requires |
221
+ |--------|--------|-----|---------|
222
+ | YouTube | ✅ | ✅ | Default |
223
+ | YouTube Music | ✅ | ✅ | Default |
224
+ | SoundCloud | ✅ | ✅ | Default |
142
225
  | Spotify | ✅ | ✅ | LavaSrc plugin |
143
226
  | Deezer | ✅ | ✅ | LavaSrc plugin |
144
227
  | Apple Music | ✅ | ✅ | LavaSrc plugin |
@@ -148,5 +231,19 @@ yukimu.on("nodeDisconnect", (node, code, reason) => {});
148
231
 
149
232
  ---
150
233
 
151
- MIT License
234
+ ## v3 vs v4
235
+
236
+ Each node can run a different version:
237
+
238
+ ```ts
239
+ nodes: [
240
+ { name: "v4", host: "...", port: 2333, password: "...", version: 4 },
241
+ { name: "v3", host: "...", port: 2334, password: "...", version: 3 },
242
+ ]
243
+ ```
244
+
245
+ Yukimu handles all differences internally — your bot code stays the same.
246
+
247
+ ---
152
248
 
249
+ MIT License | Made by prankxD
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yukimu",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "A powerful Lavalink v4 wrapper for Discord bots — supports YouTube, Spotify, Deezer, Apple Music, JioSaavn, Tidal, SoundCloud and more",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -0,0 +1,133 @@
1
+ import type { Yukimu } from "./Yukimu";
2
+
3
+ export interface VoiceConnection {
4
+ guildId: string;
5
+ channelId: string;
6
+ sessionId: string | null;
7
+ token: string | null;
8
+ endpoint: string | null;
9
+ timeout: ReturnType<typeof setTimeout> | null;
10
+ retryTimeout: ReturnType<typeof setTimeout> | null;
11
+ connected: boolean;
12
+ retries: number;
13
+ }
14
+
15
+ const MAX_VOICE_RETRIES = 3;
16
+ const VOICE_RETRY_DELAY = 5000;
17
+
18
+ export class ConnectionPool {
19
+ private readonly manager: Yukimu;
20
+ private readonly connections: Map<string, VoiceConnection> = new Map();
21
+
22
+ constructor(manager: Yukimu) {
23
+ this.manager = manager;
24
+ }
25
+
26
+ public add(guildId: string, channelId: string): VoiceConnection {
27
+ const existing = this.connections.get(guildId);
28
+ if (existing) { existing.channelId = channelId; return existing; }
29
+
30
+ const conn: VoiceConnection = {
31
+ guildId, channelId,
32
+ sessionId: null, token: null, endpoint: null,
33
+ timeout: null, retryTimeout: null,
34
+ connected: false, retries: 0,
35
+ };
36
+ this.connections.set(guildId, conn);
37
+ this.startTimeout(conn);
38
+ return conn;
39
+ }
40
+
41
+ public get(guildId: string): VoiceConnection | undefined {
42
+ return this.connections.get(guildId);
43
+ }
44
+
45
+ public remove(guildId: string): void {
46
+ const conn = this.connections.get(guildId);
47
+ if (!conn) return;
48
+ if (conn.timeout) clearTimeout(conn.timeout);
49
+ if (conn.retryTimeout) clearTimeout(conn.retryTimeout);
50
+ this.connections.delete(guildId);
51
+ }
52
+
53
+ public has(guildId: string): boolean {
54
+ return this.connections.has(guildId);
55
+ }
56
+
57
+ public updateSession(guildId: string, sessionId: string, channelId?: string): void {
58
+ const conn = this.connections.get(guildId);
59
+ if (!conn) return;
60
+ conn.sessionId = sessionId;
61
+ if (channelId) conn.channelId = channelId;
62
+ }
63
+
64
+ public updateServer(guildId: string, token: string, endpoint: string): void {
65
+ const conn = this.connections.get(guildId);
66
+ if (!conn) return;
67
+ conn.token = token;
68
+ conn.endpoint = endpoint;
69
+ }
70
+
71
+ public markConnected(guildId: string): void {
72
+ const conn = this.connections.get(guildId);
73
+ if (!conn) return;
74
+ conn.connected = true;
75
+ conn.retries = 0;
76
+ if (conn.timeout) { clearTimeout(conn.timeout); conn.timeout = null; }
77
+ if (conn.retryTimeout) { clearTimeout(conn.retryTimeout); conn.retryTimeout = null; }
78
+ }
79
+
80
+ public isReady(guildId: string): boolean {
81
+ const conn = this.connections.get(guildId);
82
+ return !!(conn?.sessionId && conn?.token && conn?.endpoint);
83
+ }
84
+
85
+ public getVoiceState(guildId: string): { token: string; endpoint: string; sessionId: string } | null {
86
+ const conn = this.connections.get(guildId);
87
+ if (!conn?.sessionId || !conn?.token || !conn?.endpoint) return null;
88
+ return { token: conn.token, endpoint: conn.endpoint, sessionId: conn.sessionId };
89
+ }
90
+
91
+ private startTimeout(conn: VoiceConnection): void {
92
+ const timeoutMs = (this.manager.options as { voiceConnectionTimeout?: number }).voiceConnectionTimeout ?? 15000;
93
+ if (conn.timeout) clearTimeout(conn.timeout);
94
+ conn.timeout = setTimeout(() => {
95
+ if (!conn.connected) this.handleConnectionFailure(conn);
96
+ }, timeoutMs);
97
+ }
98
+
99
+ private handleConnectionFailure(conn: VoiceConnection): void {
100
+ if (conn.retries >= MAX_VOICE_RETRIES) {
101
+ const player = this.manager.players.get(conn.guildId);
102
+ if (player) {
103
+ this.manager.emit("playerError" as never, player as never,
104
+ new Error(`Voice connection failed after ${MAX_VOICE_RETRIES} retries`) as never
105
+ );
106
+ this.manager.destroyPlayer(conn.guildId).catch(() => {});
107
+ }
108
+ this.remove(conn.guildId);
109
+ return;
110
+ }
111
+
112
+ conn.retries++;
113
+ const player = this.manager.players.get(conn.guildId);
114
+ if (player) {
115
+ console.warn(`[Yukimu] 🔄 Voice retry ${conn.retries}/${MAX_VOICE_RETRIES} for guild ${conn.guildId}`);
116
+ conn.retryTimeout = setTimeout(() => {
117
+ // Re-send join payload via connector
118
+ this.manager.connector.sendPayload(conn.guildId, {
119
+ op: 4,
120
+ d: {
121
+ guild_id: conn.guildId,
122
+ channel_id: conn.channelId,
123
+ self_deaf: true,
124
+ self_mute: false,
125
+ },
126
+ });
127
+ this.startTimeout(conn);
128
+ }, VOICE_RETRY_DELAY * conn.retries);
129
+ }
130
+ }
131
+
132
+ get size(): number { return this.connections.size; }
133
+ }