Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d068a6fb01 |
No files matched your search
+14
-2
@@ -1,2 +1,14 @@
|
|||||||
node_modules
|
# Ignore everything by default
|
||||||
Procfile
|
*
|
||||||
|
|
||||||
|
# Dockerfile
|
||||||
|
!Dockerfile
|
||||||
|
|
||||||
|
# Source
|
||||||
|
!src/
|
||||||
|
|
||||||
|
# Dependencies
|
||||||
|
!package*.json
|
||||||
|
|
||||||
|
# Typescript compiller config
|
||||||
|
!tsconfig.json
|
||||||
+18
-13
@@ -1,15 +1,20 @@
|
|||||||
{
|
{
|
||||||
"env": { "browser": true, "es2021": true },
|
"root": true,
|
||||||
"extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
|
"parser": "@typescript-eslint/parser",
|
||||||
"parser": "@typescript-eslint/parser",
|
"parserOptions": {
|
||||||
"parserOptions": { "ecmaVersion": "latest", "sourceType": "module" },
|
"warnOnUnsupportedTypeScriptVersion": false,
|
||||||
"plugins": ["@typescript-eslint"],
|
"sourceType": "module"
|
||||||
"rules": {
|
},
|
||||||
"indent": ["error", 4],
|
"env": {
|
||||||
"linebreak-style": ["error", "windows"],
|
"browser": false,
|
||||||
"quotes": ["error", "double"],
|
"node": true,
|
||||||
"semi": ["error", "always"],
|
"es6": true
|
||||||
"brace-style": ["error", "stroustrup"],
|
},
|
||||||
"arrow-body-style": ["error", "as-needed"]
|
"extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended", "prettier"],
|
||||||
}
|
"plugins": ["@typescript-eslint", "import", "simple-import-sort"],
|
||||||
|
"ignorePatterns": ["**/node_modules/**", "/dist/**", "/tests/**"],
|
||||||
|
"rules": {
|
||||||
|
"simple-import-sort/imports": "error",
|
||||||
|
"simple-import-sort/exports": "error"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
###############################################################################
|
|
||||||
# Set default behavior to automatically normalize line endings.
|
|
||||||
###############################################################################
|
|
||||||
* text=auto
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# Set default behavior for command prompt diff.
|
|
||||||
#
|
|
||||||
# This is need for earlier builds of msysgit that does not have it on by
|
|
||||||
# default for csharp files.
|
|
||||||
# Note: This is only used by command line
|
|
||||||
###############################################################################
|
|
||||||
#*.cs diff=csharp
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# Set the merge driver for project and solution files
|
|
||||||
#
|
|
||||||
# Merging from the command prompt will add diff markers to the files if there
|
|
||||||
# are conflicts (Merging from VS is not affected by the settings below, in VS
|
|
||||||
# the diff markers are never inserted). Diff markers may cause the following
|
|
||||||
# file extensions to fail to load in VS. An alternative would be to treat
|
|
||||||
# these files as binary and thus will always conflict and require user
|
|
||||||
# intervention with every merge. To do so, just uncomment the entries below
|
|
||||||
###############################################################################
|
|
||||||
#*.sln merge=binary
|
|
||||||
#*.csproj merge=binary
|
|
||||||
#*.vbproj merge=binary
|
|
||||||
#*.vcxproj merge=binary
|
|
||||||
#*.vcproj merge=binary
|
|
||||||
#*.dbproj merge=binary
|
|
||||||
#*.fsproj merge=binary
|
|
||||||
#*.lsproj merge=binary
|
|
||||||
#*.wixproj merge=binary
|
|
||||||
#*.modelproj merge=binary
|
|
||||||
#*.sqlproj merge=binary
|
|
||||||
#*.wwaproj merge=binary
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# behavior for image files
|
|
||||||
#
|
|
||||||
# image files are treated as binary by default.
|
|
||||||
###############################################################################
|
|
||||||
#*.jpg binary
|
|
||||||
#*.png binary
|
|
||||||
#*.gif binary
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# diff behavior for common document formats
|
|
||||||
#
|
|
||||||
# Convert binary document formats to text before diffing them. This feature
|
|
||||||
# is only available from the command line. Turn it on by uncommenting the
|
|
||||||
# entries below.
|
|
||||||
###############################################################################
|
|
||||||
#*.doc diff=astextplain
|
|
||||||
#*.DOC diff=astextplain
|
|
||||||
#*.docx diff=astextplain
|
|
||||||
#*.DOCX diff=astextplain
|
|
||||||
#*.dot diff=astextplain
|
|
||||||
#*.DOT diff=astextplain
|
|
||||||
#*.pdf diff=astextplain
|
|
||||||
#*.PDF diff=astextplain
|
|
||||||
#*.rtf diff=astextplain
|
|
||||||
#*.RTF diff=astextplain
|
|
||||||
+51
-364
@@ -1,374 +1,61 @@
|
|||||||
## Ignore Visual Studio temporary files, build results, and
|
# Logs
|
||||||
## files generated by popular Visual Studio add-ons.
|
logs
|
||||||
##
|
|
||||||
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
|
||||||
|
|
||||||
# User-specific files
|
|
||||||
*.rsuser
|
|
||||||
*.suo
|
|
||||||
*.user
|
|
||||||
*.userosscache
|
|
||||||
*.sln.docstates
|
|
||||||
|
|
||||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
|
||||||
*.userprefs
|
|
||||||
|
|
||||||
# Mono auto generated files
|
|
||||||
mono_crash.*
|
|
||||||
|
|
||||||
# Build results
|
|
||||||
[Dd]ebug/
|
|
||||||
[Dd]ebugPublic/
|
|
||||||
[Rr]elease/
|
|
||||||
[Rr]eleases/
|
|
||||||
x64/
|
|
||||||
x86/
|
|
||||||
[Ww][Ii][Nn]32/
|
|
||||||
[Aa][Rr][Mm]/
|
|
||||||
[Aa][Rr][Mm]64/
|
|
||||||
bld/
|
|
||||||
[Bb]in/
|
|
||||||
[Oo]bj/
|
|
||||||
[Oo]ut/
|
|
||||||
[Ll]og/
|
|
||||||
[Ll]ogs/
|
|
||||||
|
|
||||||
# Visual Studio 2015/2017 cache/options directory
|
|
||||||
.vs/
|
|
||||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
|
||||||
#wwwroot/
|
|
||||||
|
|
||||||
# Visual Studio 2017 auto generated files
|
|
||||||
Generated\ Files/
|
|
||||||
|
|
||||||
# MSTest test Results
|
|
||||||
[Tt]est[Rr]esult*/
|
|
||||||
[Bb]uild[Ll]og.*
|
|
||||||
|
|
||||||
# NUnit
|
|
||||||
*.VisualState.xml
|
|
||||||
TestResult.xml
|
|
||||||
nunit-*.xml
|
|
||||||
|
|
||||||
# Build Results of an ATL Project
|
|
||||||
[Dd]ebugPS/
|
|
||||||
[Rr]eleasePS/
|
|
||||||
dlldata.c
|
|
||||||
|
|
||||||
# Benchmark Results
|
|
||||||
BenchmarkDotNet.Artifacts/
|
|
||||||
|
|
||||||
# .NET Core
|
|
||||||
project.lock.json
|
|
||||||
project.fragment.lock.json
|
|
||||||
artifacts/
|
|
||||||
|
|
||||||
# ASP.NET Scaffolding
|
|
||||||
ScaffoldingReadMe.txt
|
|
||||||
|
|
||||||
# StyleCop
|
|
||||||
StyleCopReport.xml
|
|
||||||
|
|
||||||
# Files built by Visual Studio
|
|
||||||
*_i.c
|
|
||||||
*_p.c
|
|
||||||
*_h.h
|
|
||||||
*.ilk
|
|
||||||
*.meta
|
|
||||||
*.obj
|
|
||||||
*.iobj
|
|
||||||
*.pch
|
|
||||||
*.pdb
|
|
||||||
*.ipdb
|
|
||||||
*.pgc
|
|
||||||
*.pgd
|
|
||||||
*.rsp
|
|
||||||
*.sbr
|
|
||||||
*.tlb
|
|
||||||
*.tli
|
|
||||||
*.tlh
|
|
||||||
*.tmp
|
|
||||||
*.tmp_proj
|
|
||||||
*_wpftmp.csproj
|
|
||||||
*.log
|
*.log
|
||||||
*.vspscc
|
npm-debug.log*
|
||||||
*.vssscc
|
yarn-debug.log*
|
||||||
.builds
|
yarn-error.log*
|
||||||
*.pidb
|
lerna-debug.log*
|
||||||
*.svclog
|
.pnpm-debug.log*
|
||||||
*.scc
|
|
||||||
|
|
||||||
# Chutzpah Test files
|
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||||
_Chutzpah*
|
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||||
|
|
||||||
# Visual C++ cache files
|
# Runtime data
|
||||||
ipch/
|
pids
|
||||||
*.aps
|
*.pid
|
||||||
*.ncb
|
*.seed
|
||||||
*.opendb
|
*.pid.lock
|
||||||
*.opensdf
|
|
||||||
*.sdf
|
|
||||||
*.cachefile
|
|
||||||
*.VC.db
|
|
||||||
*.VC.VC.opendb
|
|
||||||
|
|
||||||
# Visual Studio profiler
|
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||||
*.psess
|
build/Release
|
||||||
*.vsp
|
|
||||||
*.vspx
|
|
||||||
*.sap
|
|
||||||
|
|
||||||
# Visual Studio Trace Files
|
# Dependency directories
|
||||||
*.e2e
|
|
||||||
|
|
||||||
# TFS 2012 Local Workspace
|
|
||||||
$tf/
|
|
||||||
|
|
||||||
# Guidance Automation Toolkit
|
|
||||||
*.gpState
|
|
||||||
|
|
||||||
# ReSharper is a .NET coding add-in
|
|
||||||
_ReSharper*/
|
|
||||||
*.[Rr]e[Ss]harper
|
|
||||||
*.DotSettings.user
|
|
||||||
|
|
||||||
# TeamCity is a build add-in
|
|
||||||
_TeamCity*
|
|
||||||
|
|
||||||
# DotCover is a Code Coverage Tool
|
|
||||||
*.dotCover
|
|
||||||
|
|
||||||
# AxoCover is a Code Coverage Tool
|
|
||||||
.axoCover/*
|
|
||||||
!.axoCover/settings.json
|
|
||||||
|
|
||||||
# Coverlet is a free, cross platform Code Coverage Tool
|
|
||||||
coverage*.json
|
|
||||||
coverage*.xml
|
|
||||||
coverage*.info
|
|
||||||
|
|
||||||
# Visual Studio code coverage results
|
|
||||||
*.coverage
|
|
||||||
*.coveragexml
|
|
||||||
|
|
||||||
# NCrunch
|
|
||||||
_NCrunch_*
|
|
||||||
.*crunch*.local.xml
|
|
||||||
nCrunchTemp_*
|
|
||||||
|
|
||||||
# MightyMoose
|
|
||||||
*.mm.*
|
|
||||||
AutoTest.Net/
|
|
||||||
|
|
||||||
# Web workbench (sass)
|
|
||||||
.sass-cache/
|
|
||||||
|
|
||||||
# Installshield output folder
|
|
||||||
[Ee]xpress/
|
|
||||||
|
|
||||||
# DocProject is a documentation generator add-in
|
|
||||||
DocProject/buildhelp/
|
|
||||||
DocProject/Help/*.HxT
|
|
||||||
DocProject/Help/*.HxC
|
|
||||||
DocProject/Help/*.hhc
|
|
||||||
DocProject/Help/*.hhk
|
|
||||||
DocProject/Help/*.hhp
|
|
||||||
DocProject/Help/Html2
|
|
||||||
DocProject/Help/html
|
|
||||||
|
|
||||||
# Click-Once directory
|
|
||||||
publish/
|
|
||||||
|
|
||||||
# Publish Web Output
|
|
||||||
*.[Pp]ublish.xml
|
|
||||||
*.azurePubxml
|
|
||||||
# Note: Comment the next line if you want to checkin your web deploy settings,
|
|
||||||
# but database connection strings (with potential passwords) will be unencrypted
|
|
||||||
*.pubxml
|
|
||||||
*.publishproj
|
|
||||||
|
|
||||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
|
||||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
|
||||||
# in these scripts will be unencrypted
|
|
||||||
PublishScripts/
|
|
||||||
|
|
||||||
# NuGet Packages
|
|
||||||
*.nupkg
|
|
||||||
# NuGet Symbol Packages
|
|
||||||
*.snupkg
|
|
||||||
# The packages folder can be ignored because of Package Restore
|
|
||||||
**/[Pp]ackages/*
|
|
||||||
# except build/, which is used as an MSBuild target.
|
|
||||||
!**/[Pp]ackages/build/
|
|
||||||
# Uncomment if necessary however generally it will be regenerated when needed
|
|
||||||
#!**/[Pp]ackages/repositories.config
|
|
||||||
# NuGet v3's project.json files produces more ignorable files
|
|
||||||
*.nuget.props
|
|
||||||
*.nuget.targets
|
|
||||||
|
|
||||||
# Microsoft Azure Build Output
|
|
||||||
csx/
|
|
||||||
*.build.csdef
|
|
||||||
|
|
||||||
# Microsoft Azure Emulator
|
|
||||||
ecf/
|
|
||||||
rcf/
|
|
||||||
|
|
||||||
# Windows Store app package directories and files
|
|
||||||
AppPackages/
|
|
||||||
BundleArtifacts/
|
|
||||||
Package.StoreAssociation.xml
|
|
||||||
_pkginfo.txt
|
|
||||||
*.appx
|
|
||||||
*.appxbundle
|
|
||||||
*.appxupload
|
|
||||||
|
|
||||||
# Visual Studio cache files
|
|
||||||
# files ending in .cache can be ignored
|
|
||||||
*.[Cc]ache
|
|
||||||
# but keep track of directories ending in .cache
|
|
||||||
!?*.[Cc]ache/
|
|
||||||
|
|
||||||
# Others
|
|
||||||
ClientBin/
|
|
||||||
~$*
|
|
||||||
*~
|
|
||||||
*.dbmdl
|
|
||||||
*.dbproj.schemaview
|
|
||||||
*.jfm
|
|
||||||
*.pfx
|
|
||||||
*.publishsettings
|
|
||||||
orleans.codegen.cs
|
|
||||||
|
|
||||||
# Including strong name files can present a security risk
|
|
||||||
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
|
||||||
#*.snk
|
|
||||||
|
|
||||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
|
||||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
|
||||||
#bower_components/
|
|
||||||
|
|
||||||
# RIA/Silverlight projects
|
|
||||||
Generated_Code/
|
|
||||||
|
|
||||||
# Backup & report files from converting an old project file
|
|
||||||
# to a newer Visual Studio version. Backup files are not needed,
|
|
||||||
# because we have git ;-)
|
|
||||||
_UpgradeReport_Files/
|
|
||||||
Backup*/
|
|
||||||
UpgradeLog*.XML
|
|
||||||
UpgradeLog*.htm
|
|
||||||
ServiceFabricBackup/
|
|
||||||
*.rptproj.bak
|
|
||||||
|
|
||||||
# SQL Server files
|
|
||||||
*.mdf
|
|
||||||
*.ldf
|
|
||||||
*.ndf
|
|
||||||
|
|
||||||
# Business Intelligence projects
|
|
||||||
*.rdl.data
|
|
||||||
*.bim.layout
|
|
||||||
*.bim_*.settings
|
|
||||||
*.rptproj.rsuser
|
|
||||||
*- [Bb]ackup.rdl
|
|
||||||
*- [Bb]ackup ([0-9]).rdl
|
|
||||||
*- [Bb]ackup ([0-9][0-9]).rdl
|
|
||||||
|
|
||||||
# Microsoft Fakes
|
|
||||||
FakesAssemblies/
|
|
||||||
|
|
||||||
# GhostDoc plugin setting file
|
|
||||||
*.GhostDoc.xml
|
|
||||||
|
|
||||||
# Node.js Tools for Visual Studio
|
|
||||||
.ntvs_analysis.dat
|
|
||||||
node_modules/
|
node_modules/
|
||||||
|
jspm_packages/
|
||||||
|
|
||||||
# Visual Studio 6 build log
|
# TypeScript cache
|
||||||
*.plg
|
*.tsbuildinfo
|
||||||
|
|
||||||
# Visual Studio 6 workspace options file
|
|
||||||
*.opt
|
|
||||||
|
|
||||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
|
||||||
*.vbw
|
|
||||||
|
|
||||||
# Visual Studio LightSwitch build output
|
|
||||||
**/*.HTMLClient/GeneratedArtifacts
|
|
||||||
**/*.DesktopClient/GeneratedArtifacts
|
|
||||||
**/*.DesktopClient/ModelManifest.xml
|
|
||||||
**/*.Server/GeneratedArtifacts
|
|
||||||
**/*.Server/ModelManifest.xml
|
|
||||||
_Pvt_Extensions
|
|
||||||
|
|
||||||
# Paket dependency manager
|
|
||||||
.paket/paket.exe
|
|
||||||
paket-files/
|
|
||||||
|
|
||||||
# FAKE - F# Make
|
|
||||||
.fake/
|
|
||||||
|
|
||||||
# CodeRush personal settings
|
|
||||||
.cr/personal
|
|
||||||
|
|
||||||
# Python Tools for Visual Studio (PTVS)
|
|
||||||
__pycache__/
|
|
||||||
*.pyc
|
|
||||||
|
|
||||||
# Cake - Uncomment if you are using it
|
|
||||||
# tools/**
|
|
||||||
# !tools/packages.config
|
|
||||||
|
|
||||||
# Tabs Studio
|
|
||||||
*.tss
|
|
||||||
|
|
||||||
# Telerik's JustMock configuration file
|
|
||||||
*.jmconfig
|
|
||||||
|
|
||||||
# BizTalk build output
|
|
||||||
*.btp.cs
|
|
||||||
*.btm.cs
|
|
||||||
*.odx.cs
|
|
||||||
*.xsd.cs
|
|
||||||
|
|
||||||
# OpenCover UI analysis results
|
|
||||||
OpenCover/
|
|
||||||
|
|
||||||
# Azure Stream Analytics local run output
|
|
||||||
ASALocalRun/
|
|
||||||
|
|
||||||
# MSBuild Binary and Structured Log
|
|
||||||
*.binlog
|
|
||||||
|
|
||||||
# NVidia Nsight GPU debugger configuration file
|
|
||||||
*.nvuser
|
|
||||||
|
|
||||||
# MFractors (Xamarin productivity tool) working folder
|
|
||||||
.mfractor/
|
|
||||||
|
|
||||||
# Local History for Visual Studio
|
|
||||||
.localhistory/
|
|
||||||
|
|
||||||
# BeatPulse healthcheck temp database
|
|
||||||
healthchecksdb
|
|
||||||
|
|
||||||
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
|
||||||
MigrationBackup/
|
|
||||||
|
|
||||||
# Ionide (cross platform F# VS Code tools) working folder
|
|
||||||
.ionide/
|
|
||||||
|
|
||||||
# Fody - auto-generated XML schema
|
|
||||||
FodyWeavers.xsd
|
|
||||||
|
|
||||||
# assetscript restrictions
|
|
||||||
dist/
|
dist/
|
||||||
*.js
|
|
||||||
*.js.map
|
|
||||||
|
|
||||||
# binaries is not bundled
|
# Optional npm cache directory
|
||||||
bin/
|
.npm
|
||||||
|
|
||||||
# Keep enviromental variables out of version control
|
# Optional eslint cache
|
||||||
*.env
|
.eslintcache
|
||||||
|
|
||||||
|
# Optional REPL history
|
||||||
|
.node_repl_history
|
||||||
|
|
||||||
|
# Output of 'npm pack'
|
||||||
|
*.tgz
|
||||||
|
|
||||||
|
# Yarn Integrity file
|
||||||
|
.yarn-integrity
|
||||||
|
|
||||||
|
# dotenv environment variable files
|
||||||
|
.env
|
||||||
|
.env.development.local
|
||||||
|
.env.test.local
|
||||||
|
.env.production.local
|
||||||
|
.env.local
|
||||||
|
|
||||||
|
# VSCode
|
||||||
|
.vscode-test
|
||||||
|
.vscode
|
||||||
|
|
||||||
|
# yarn v2
|
||||||
|
.yarn/cache
|
||||||
|
.yarn/unplugged
|
||||||
|
.yarn/build-state.yml
|
||||||
|
.yarn/install-state.gz
|
||||||
|
.pnp.*
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
# Node.js Tools
|
||||||
|
node_modules
|
||||||
|
|
||||||
|
# Typescript compiller artifacts
|
||||||
|
dist/
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"semi": true,
|
||||||
|
"trailingComma": "none",
|
||||||
|
"singleQuote": false,
|
||||||
|
"printWidth": 100,
|
||||||
|
"arrowParens": "always",
|
||||||
|
"bracketSpacing": true,
|
||||||
|
"endOfLine": "crlf",
|
||||||
|
"overrides": [
|
||||||
|
{
|
||||||
|
"files": ["**/*.json, **/*.yml"],
|
||||||
|
"options": {
|
||||||
|
"tabWidth": 2
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"files": ["**/*.ts"],
|
||||||
|
"options": {
|
||||||
|
"tabWidth": 4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
+1
-1
@@ -16,6 +16,6 @@ COPY package*.json ./
|
|||||||
RUN npm ci
|
RUN npm ci
|
||||||
|
|
||||||
COPY . .
|
COPY . .
|
||||||
run npm run build
|
RUN npm run build
|
||||||
|
|
||||||
CMD [ "npm", "start" ]
|
CMD [ "npm", "start" ]
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
# Quetza - 2302.1 <soundrewrite>
|
# Quetza - 2302.1
|
||||||
|
|
||||||
_Neat typescript discord bot._
|
_Neat typescript discord bot._
|
||||||
|
|
||||||
|
|||||||
Generated
+970
-3
File diff suppressed because it is too large.
Load diff
+13
-9
@@ -5,7 +5,7 @@
|
|||||||
"npm": "*"
|
"npm": "*"
|
||||||
},
|
},
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"version": "2302.1.0",
|
"version": "2302.1",
|
||||||
"description": "Discord multifunctional bot",
|
"description": "Discord multifunctional bot",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "unknowableshade",
|
"name": "unknowableshade",
|
||||||
@@ -23,24 +23,28 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"poststart": "npm run build",
|
|
||||||
"start": "node dist/index.js",
|
"start": "node dist/index.js",
|
||||||
"build": "tsc --build",
|
"build": "npx tsc --build",
|
||||||
"clean": "tsc --build --clean"
|
"clean": "npx tsc --build --clean",
|
||||||
|
"lint": "npx prettier --write . && npx eslint --fix .",
|
||||||
|
"prestart": "npm run build"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"discord.js": "^14.3.0",
|
||||||
"@discordjs/opus": "^0.8.0",
|
"@discordjs/opus": "^0.8.0",
|
||||||
"@discordjs/voice": "^0.11.0",
|
"@discordjs/voice": "^0.11.0",
|
||||||
|
"ytdl-core": "^4.11.1",
|
||||||
"discord-ytdl-core": "^5.0.4",
|
"discord-ytdl-core": "^5.0.4",
|
||||||
"discord.js": "^14.3.0",
|
"tweetnacl": "^1.0.3"
|
||||||
"tweetnacl": "^1.0.3",
|
|
||||||
"ytdl-core": "^4.11.1"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"typescript": "^4.8.2",
|
||||||
"@types/node": "^18.7.13",
|
"@types/node": "^18.7.13",
|
||||||
|
"eslint": "^8.22.0",
|
||||||
|
"eslint-config-prettier": "^8.6.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.35.1",
|
"@typescript-eslint/eslint-plugin": "^5.35.1",
|
||||||
"@typescript-eslint/parser": "^5.35.1",
|
"@typescript-eslint/parser": "^5.35.1",
|
||||||
"eslint": "^8.22.0",
|
"eslint-plugin-import": "^2.27.5",
|
||||||
"typescript": "^4.8.2"
|
"eslint-plugin-simple-import-sort": "^10.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import Client from "../lib/Client.js";
|
|
||||||
|
|
||||||
import { CommandInteraction, SlashCommandBuilder, TextChannel } from "discord.js";
|
import { CommandInteraction, SlashCommandBuilder, TextChannel } from "discord.js";
|
||||||
import I18n from "../lib/I18n.js";
|
|
||||||
|
import Client from "../lib/client.js";
|
||||||
|
import I18n from "../lib/i18n.js";
|
||||||
|
|
||||||
export async function run(client: Client, ctx: CommandInteraction) {
|
export async function run(client: Client, ctx: CommandInteraction) {
|
||||||
if (!ctx.guild || !ctx.channel) return;
|
if (!ctx.guild || !ctx.channel) return;
|
||||||
@@ -17,8 +17,6 @@ export async function run(client: Client, ctx: CommandInteraction) {
|
|||||||
await ctx.reply({ embeds: [I18n.en.cleared(amount)] });
|
await ctx.reply({ embeds: [I18n.en.cleared(amount)] });
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = new SlashCommandBuilder()
|
const data = new SlashCommandBuilder().setName("clear").setDescription("Clear the player's queue.");
|
||||||
.setName("clear")
|
|
||||||
.setDescription("Clear the player's queue.");
|
|
||||||
|
|
||||||
export { data };
|
export { data };
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import Client from "../lib/Client.js";
|
|
||||||
|
|
||||||
import { CommandInteraction, GuildMember, SlashCommandBuilder, TextChannel } from "discord.js";
|
import { CommandInteraction, GuildMember, SlashCommandBuilder, TextChannel } from "discord.js";
|
||||||
import I18n from "../lib/I18n.js";
|
|
||||||
|
import Client from "../lib/client.js";
|
||||||
|
import I18n from "../lib/i18n.js";
|
||||||
|
|
||||||
export async function run(client: Client, ctx: CommandInteraction) {
|
export async function run(client: Client, ctx: CommandInteraction) {
|
||||||
if (!ctx.guild || !ctx.channel || !ctx.member) return;
|
if (!ctx.guild || !ctx.channel || !ctx.member) return;
|
||||||
@@ -18,15 +18,13 @@ export async function run(client: Client, ctx: CommandInteraction) {
|
|||||||
player.connect(channel);
|
player.connect(channel);
|
||||||
|
|
||||||
await ctx.editReply({ embeds: [I18n.en.okConnected(channel.name)] });
|
await ctx.editReply({ embeds: [I18n.en.okConnected(channel.name)] });
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
client.modules.music.del(ctx.guild.id);
|
client.modules.music.del(ctx.guild.id);
|
||||||
|
|
||||||
await ctx.editReply({ embeds: [I18n.en.notConnected()] });
|
await ctx.editReply({ embeds: [I18n.en.notConnected()] });
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
await ctx.editReply({ embeds: [I18n.en.wasConnected()] });
|
await ctx.editReply({ embeds: [I18n.en.wasConnected()] });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+102
-99
@@ -1,6 +1,7 @@
|
|||||||
import { CommandInteraction, SlashCommandBuilder, TextChannel } from "discord.js";
|
import { CommandInteraction, SlashCommandBuilder, TextChannel } from "discord.js";
|
||||||
import Client from "../lib/Client.js";
|
|
||||||
import I18n from "../lib/I18n.js";
|
import Client from "../lib/client.js";
|
||||||
|
import I18n from "../lib/i18n.js";
|
||||||
|
|
||||||
export async function run(client: Client, ctx: CommandInteraction) {
|
export async function run(client: Client, ctx: CommandInteraction) {
|
||||||
const filter = ctx.options.get("filter")?.value as string;
|
const filter = ctx.options.get("filter")?.value as string;
|
||||||
@@ -19,103 +20,105 @@ export async function run(client: Client, ctx: CommandInteraction) {
|
|||||||
const data = new SlashCommandBuilder()
|
const data = new SlashCommandBuilder()
|
||||||
.setName("filter")
|
.setName("filter")
|
||||||
.setDescription("Apply unique filters to the tracks.")
|
.setDescription("Apply unique filters to the tracks.")
|
||||||
.addStringOption(option => option
|
.addStringOption((option) =>
|
||||||
.setName("filter")
|
option
|
||||||
.setDescription("Filter to apply.")
|
.setName("filter")
|
||||||
.setChoices(
|
.setDescription("Filter to apply.")
|
||||||
{
|
.setChoices(
|
||||||
name: "bassboost_low",
|
{
|
||||||
value: "bassboost_low",
|
name: "bassboost_low",
|
||||||
},
|
value: "bassboost_low"
|
||||||
{
|
},
|
||||||
name: "bassboost",
|
{
|
||||||
value: "bassboost",
|
name: "bassboost",
|
||||||
},
|
value: "bassboost"
|
||||||
{
|
},
|
||||||
name: "bassboost_high",
|
{
|
||||||
value: "bassboost_high",
|
name: "bassboost_high",
|
||||||
},
|
value: "bassboost_high"
|
||||||
{
|
},
|
||||||
name: "8D",
|
{
|
||||||
value: "8D",
|
name: "8D",
|
||||||
},
|
value: "8D"
|
||||||
{
|
},
|
||||||
name: "vaporwave",
|
{
|
||||||
value: "vaporwave",
|
name: "vaporwave",
|
||||||
},
|
value: "vaporwave"
|
||||||
{
|
},
|
||||||
name: "nightcore",
|
{
|
||||||
value: "nightcore",
|
name: "nightcore",
|
||||||
},
|
value: "nightcore"
|
||||||
{
|
},
|
||||||
name: "phaser",
|
{
|
||||||
value: "phaser",
|
name: "phaser",
|
||||||
},
|
value: "phaser"
|
||||||
{
|
},
|
||||||
name: "tremolo",
|
{
|
||||||
value: "tremolo",
|
name: "tremolo",
|
||||||
},
|
value: "tremolo"
|
||||||
{
|
},
|
||||||
name: "vibrato",
|
{
|
||||||
value: "vibrato",
|
name: "vibrato",
|
||||||
},
|
value: "vibrato"
|
||||||
{
|
},
|
||||||
name: "reverse",
|
{
|
||||||
value: "reverse",
|
name: "reverse",
|
||||||
},
|
value: "reverse"
|
||||||
{
|
},
|
||||||
name: "treble",
|
{
|
||||||
value: "treble",
|
name: "treble",
|
||||||
},
|
value: "treble"
|
||||||
{
|
},
|
||||||
name: "normalizer",
|
{
|
||||||
value: "normalizer",
|
name: "normalizer",
|
||||||
},
|
value: "normalizer"
|
||||||
{
|
},
|
||||||
name: "surrounding",
|
{
|
||||||
value: "surrounding",
|
name: "surrounding",
|
||||||
},
|
value: "surrounding"
|
||||||
{
|
},
|
||||||
name: "pulsator",
|
{
|
||||||
value: "pulsator",
|
name: "pulsator",
|
||||||
},
|
value: "pulsator"
|
||||||
{
|
},
|
||||||
name: "subboost",
|
{
|
||||||
value: "subboost",
|
name: "subboost",
|
||||||
},
|
value: "subboost"
|
||||||
{
|
},
|
||||||
name: "mono",
|
{
|
||||||
value: "mono",
|
name: "mono",
|
||||||
},
|
value: "mono"
|
||||||
{
|
},
|
||||||
name: "compressor",
|
{
|
||||||
value: "compressor",
|
name: "compressor",
|
||||||
},
|
value: "compressor"
|
||||||
{
|
},
|
||||||
name: "expander",
|
{
|
||||||
value: "expander",
|
name: "expander",
|
||||||
},
|
value: "expander"
|
||||||
{
|
},
|
||||||
name: "softlimiter",
|
{
|
||||||
value: "softlimiter",
|
name: "softlimiter",
|
||||||
},
|
value: "softlimiter"
|
||||||
{
|
},
|
||||||
name: "chorus",
|
{
|
||||||
value: "chorus",
|
name: "chorus",
|
||||||
},
|
value: "chorus"
|
||||||
{
|
},
|
||||||
name: "fadein",
|
{
|
||||||
value: "fadein",
|
name: "fadein",
|
||||||
},
|
value: "fadein"
|
||||||
{
|
},
|
||||||
name: "dim",
|
{
|
||||||
value: "dim",
|
name: "dim",
|
||||||
},
|
value: "dim"
|
||||||
{
|
},
|
||||||
name: "earrape",
|
{
|
||||||
value: "earrape",
|
name: "earrape",
|
||||||
})
|
value: "earrape"
|
||||||
.setRequired(true)
|
}
|
||||||
|
)
|
||||||
|
.setRequired(true)
|
||||||
);
|
);
|
||||||
|
|
||||||
export { data };
|
export { data };
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import Client from "../lib/Client.js";
|
|
||||||
|
|
||||||
import { CommandInteraction, SlashCommandBuilder, TextChannel } from "discord.js";
|
import { CommandInteraction, SlashCommandBuilder, TextChannel } from "discord.js";
|
||||||
import I18n from "../lib/I18n.js";
|
|
||||||
|
import Client from "../lib/client.js";
|
||||||
|
import I18n from "../lib/i18n.js";
|
||||||
|
|
||||||
export async function run(client: Client, ctx: CommandInteraction) {
|
export async function run(client: Client, ctx: CommandInteraction) {
|
||||||
if (!ctx.guild || !ctx.channel || !ctx.member) return;
|
if (!ctx.guild || !ctx.channel || !ctx.member) return;
|
||||||
|
|||||||
+7
-10
@@ -1,6 +1,7 @@
|
|||||||
import { CommandInteraction, SlashCommandBuilder, TextChannel } from "discord.js";
|
import { CommandInteraction, SlashCommandBuilder, TextChannel } from "discord.js";
|
||||||
import Client from "../lib/Client.js";
|
|
||||||
import I18n from "../lib/I18n.js";
|
import Client from "../lib/client.js";
|
||||||
|
import I18n from "../lib/i18n.js";
|
||||||
|
|
||||||
export async function run(client: Client, ctx: CommandInteraction) {
|
export async function run(client: Client, ctx: CommandInteraction) {
|
||||||
const pos = ctx.options.get("position")?.value as number;
|
const pos = ctx.options.get("position")?.value as number;
|
||||||
@@ -22,15 +23,11 @@ export async function run(client: Client, ctx: CommandInteraction) {
|
|||||||
const data = new SlashCommandBuilder()
|
const data = new SlashCommandBuilder()
|
||||||
.setName("insert")
|
.setName("insert")
|
||||||
.setDescription("Insert a new track to specific position in the queue.")
|
.setDescription("Insert a new track to specific position in the queue.")
|
||||||
.addStringOption(option => option
|
.addStringOption((option) =>
|
||||||
.setName("query")
|
option.setName("query").setDescription("Title or URL of the song.").setRequired(true)
|
||||||
.setDescription("Title or URL of the song.")
|
|
||||||
.setRequired(true)
|
|
||||||
)
|
)
|
||||||
.addIntegerOption(option => option
|
.addIntegerOption((option) =>
|
||||||
.setName("position")
|
option.setName("position").setDescription("Position to insert.").setRequired(true)
|
||||||
.setDescription("Position to insert.",)
|
|
||||||
.setRequired(true)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
export { data };
|
export { data };
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import { CommandInteraction, SlashCommandBuilder, TextChannel } from "discord.js";
|
import { CommandInteraction, SlashCommandBuilder, TextChannel } from "discord.js";
|
||||||
import Client from "../lib/Client.js";
|
|
||||||
import I18n from "../lib/I18n.js";
|
import Client from "../lib/client.js";
|
||||||
|
import I18n from "../lib/i18n.js";
|
||||||
|
|
||||||
export async function run(client: Client, ctx: CommandInteraction) {
|
export async function run(client: Client, ctx: CommandInteraction) {
|
||||||
const query = ctx.options.get("query")?.value as string;
|
const query = ctx.options.get("query")?.value as string;
|
||||||
@@ -11,7 +12,10 @@ export async function run(client: Client, ctx: CommandInteraction) {
|
|||||||
|
|
||||||
if (!player) return;
|
if (!player) return;
|
||||||
|
|
||||||
const state = !isNaN(+query) && isFinite(+query) && !/e/i.test(query) ? player.jump(parseInt(query) - 1) : player.jump(query);
|
const state =
|
||||||
|
!isNaN(+query) && isFinite(+query) && !/e/i.test(query)
|
||||||
|
? player.jump(parseInt(query) - 1)
|
||||||
|
: player.jump(query);
|
||||||
|
|
||||||
await ctx.reply({ embeds: [I18n.en.jumped(state)] });
|
await ctx.reply({ embeds: [I18n.en.jumped(state)] });
|
||||||
}
|
}
|
||||||
@@ -19,10 +23,8 @@ export async function run(client: Client, ctx: CommandInteraction) {
|
|||||||
const data = new SlashCommandBuilder()
|
const data = new SlashCommandBuilder()
|
||||||
.setName("jump")
|
.setName("jump")
|
||||||
.setDescription("Jump to specific track in the queue.")
|
.setDescription("Jump to specific track in the queue.")
|
||||||
.addStringOption(option => option
|
.addStringOption((option) =>
|
||||||
.setName("query")
|
option.setName("query").setDescription("Position or title to jump to.").setRequired(true)
|
||||||
.setDescription("Position or title to jump to.")
|
|
||||||
.setRequired(true)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
export { data };
|
export { data };
|
||||||
+16
-11
@@ -1,7 +1,8 @@
|
|||||||
import { CommandInteraction, SlashCommandBuilder, TextChannel } from "discord.js";
|
import { CommandInteraction, SlashCommandBuilder, TextChannel } from "discord.js";
|
||||||
import Client from "../lib/Client.js";
|
|
||||||
import { loopOption } from "../lib/Types.js";
|
import Client from "../lib/client.js";
|
||||||
import I18n from "../lib/I18n.js";
|
import I18n from "../lib/i18n.js";
|
||||||
|
import { loopOption } from "../lib/types.js";
|
||||||
|
|
||||||
export async function run(client: Client, ctx: CommandInteraction) {
|
export async function run(client: Client, ctx: CommandInteraction) {
|
||||||
const query = ctx.options.get("option")?.value as string;
|
const query = ctx.options.get("option")?.value as string;
|
||||||
@@ -20,13 +21,17 @@ export async function run(client: Client, ctx: CommandInteraction) {
|
|||||||
const data = new SlashCommandBuilder()
|
const data = new SlashCommandBuilder()
|
||||||
.setName("loop")
|
.setName("loop")
|
||||||
.setDescription("Select player's loop mode.")
|
.setDescription("Select player's loop mode.")
|
||||||
.addStringOption(option => option
|
.addStringOption((option) =>
|
||||||
.setName("option")
|
option
|
||||||
.setDescription("Select loop option.")
|
.setName("option")
|
||||||
.setChoices( { name: "loop queue", value: "LOOP" },
|
.setDescription("Select loop option.")
|
||||||
{ name: "loop single track", value: "SONG" },
|
.setChoices(
|
||||||
{ name: "Till end", value: "NONE" },
|
{ name: "loop queue", value: "LOOP" },
|
||||||
{ name: "Random order", value: "AUTO" })
|
{ name: "loop single track", value: "SONG" },
|
||||||
.setRequired(true));
|
{ name: "Till end", value: "NONE" },
|
||||||
|
{ name: "Random order", value: "AUTO" }
|
||||||
|
)
|
||||||
|
.setRequired(true)
|
||||||
|
);
|
||||||
|
|
||||||
export { data };
|
export { data };
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import { CommandInteraction, SlashCommandBuilder, TextChannel } from "discord.js";
|
import { CommandInteraction, SlashCommandBuilder, TextChannel } from "discord.js";
|
||||||
import Client from "../lib/Client.js";
|
|
||||||
import I18n from "../lib/I18n.js";
|
import Client from "../lib/client.js";
|
||||||
|
import I18n from "../lib/i18n.js";
|
||||||
|
|
||||||
export async function run(client: Client, ctx: CommandInteraction) {
|
export async function run(client: Client, ctx: CommandInteraction) {
|
||||||
if (!ctx.guild || !ctx.channel) return;
|
if (!ctx.guild || !ctx.channel) return;
|
||||||
@@ -14,8 +15,6 @@ export async function run(client: Client, ctx: CommandInteraction) {
|
|||||||
await ctx.reply({ embeds: [I18n.en.skipped()] });
|
await ctx.reply({ embeds: [I18n.en.skipped()] });
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = new SlashCommandBuilder()
|
const data = new SlashCommandBuilder().setName("next").setDescription("Skip current song.");
|
||||||
.setName("next")
|
|
||||||
.setDescription("Skip current song.");
|
|
||||||
|
|
||||||
export { data };
|
export { data };
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import { CommandInteraction, SlashCommandBuilder, TextChannel } from "discord.js";
|
import { CommandInteraction, SlashCommandBuilder, TextChannel } from "discord.js";
|
||||||
import Client from "../lib/Client.js";
|
|
||||||
import I18n from "../lib/I18n.js";
|
import Client from "../lib/client.js";
|
||||||
|
import I18n from "../lib/i18n.js";
|
||||||
|
|
||||||
export async function run(client: Client, ctx: CommandInteraction) {
|
export async function run(client: Client, ctx: CommandInteraction) {
|
||||||
if (!ctx.guild || !ctx.channel) return;
|
if (!ctx.guild || !ctx.channel) return;
|
||||||
@@ -14,8 +15,6 @@ export async function run(client: Client, ctx: CommandInteraction) {
|
|||||||
await ctx.reply({ embeds: [I18n.en.paused(state)] });
|
await ctx.reply({ embeds: [I18n.en.paused(state)] });
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = new SlashCommandBuilder()
|
const data = new SlashCommandBuilder().setName("pause").setDescription("Toggle pause on player.");
|
||||||
.setName("pause")
|
|
||||||
.setDescription("Toggle pause on player.");
|
|
||||||
|
|
||||||
export { data };
|
export { data };
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import { CommandInteraction, SlashCommandBuilder } from "discord.js";
|
import { CommandInteraction, SlashCommandBuilder } from "discord.js";
|
||||||
import Client from "../lib/Client.js";
|
|
||||||
import I18n from "../lib/I18n.js";
|
import Client from "../lib/client.js";
|
||||||
|
import I18n from "../lib/i18n.js";
|
||||||
|
|
||||||
export async function run(client: Client, ctx: CommandInteraction) {
|
export async function run(client: Client, ctx: CommandInteraction) {
|
||||||
const start = Date.now();
|
const start = Date.now();
|
||||||
@@ -15,8 +16,6 @@ export async function run(client: Client, ctx: CommandInteraction) {
|
|||||||
await ctx.reply({ embeds: [I18n.en.ping(Date.now() - start)] });
|
await ctx.reply({ embeds: [I18n.en.ping(Date.now() - start)] });
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = new SlashCommandBuilder()
|
const data = new SlashCommandBuilder().setName("ping").setDescription("Try to ping me.");
|
||||||
.setName("ping")
|
|
||||||
.setDescription("Try to ping me.");
|
|
||||||
|
|
||||||
export { data };
|
export { data };
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
import { CommandInteraction, SlashCommandBuilder } from "discord.js";
|
import { CommandInteraction, SlashCommandBuilder } from "discord.js";
|
||||||
import Client from "../lib/Client.js";
|
|
||||||
|
import Client from "../lib/client.js";
|
||||||
|
import I18n from "../lib/i18n.js";
|
||||||
import { run as connect } from "./connect.js";
|
import { run as connect } from "./connect.js";
|
||||||
import I18n from "../lib/I18n.js";
|
|
||||||
|
|
||||||
export async function run(client: Client, ctx: CommandInteraction) {
|
export async function run(client: Client, ctx: CommandInteraction) {
|
||||||
const query = ctx.options.get("query")?.value as string;
|
const query = ctx.options.get("query")?.value as string;
|
||||||
@@ -24,9 +25,8 @@ export async function run(client: Client, ctx: CommandInteraction) {
|
|||||||
const data = new SlashCommandBuilder()
|
const data = new SlashCommandBuilder()
|
||||||
.setName("play")
|
.setName("play")
|
||||||
.setDescription("Launch player and add songs to the queue.")
|
.setDescription("Launch player and add songs to the queue.")
|
||||||
.addStringOption(option => option
|
.addStringOption((option) =>
|
||||||
.setName("query")
|
option.setName("query").setDescription("Title or URL of the song.")
|
||||||
.setDescription("Title or URL of the song.")
|
|
||||||
);
|
);
|
||||||
|
|
||||||
export { data };
|
export { data };
|
||||||
+23
-37
@@ -10,8 +10,8 @@ import {
|
|||||||
TextChannel
|
TextChannel
|
||||||
} from "discord.js";
|
} from "discord.js";
|
||||||
|
|
||||||
import Client from "../lib/Client.js";
|
import Client from "../lib/client.js";
|
||||||
import I18n from "../lib/I18n.js";
|
import I18n from "../lib/i18n.js";
|
||||||
|
|
||||||
export async function run(client: Client, ctx: CommandInteraction) {
|
export async function run(client: Client, ctx: CommandInteraction) {
|
||||||
if (!ctx.guild || !ctx.channel) return;
|
if (!ctx.guild || !ctx.channel) return;
|
||||||
@@ -30,57 +30,43 @@ export async function run(client: Client, ctx: CommandInteraction) {
|
|||||||
let page = 0;
|
let page = 0;
|
||||||
|
|
||||||
const row = new ActionRowBuilder<MessageActionRowComponentBuilder>().addComponents(
|
const row = new ActionRowBuilder<MessageActionRowComponentBuilder>().addComponents(
|
||||||
new ButtonBuilder()
|
new ButtonBuilder().setCustomId("QueueTop").setLabel("🔼").setStyle(ButtonStyle.Primary),
|
||||||
.setCustomId("QueueTop")
|
new ButtonBuilder().setCustomId("QueueUp").setLabel("🔺").setStyle(ButtonStyle.Secondary),
|
||||||
.setLabel("🔼")
|
new ButtonBuilder().setCustomId("QueueDown").setLabel("🔻").setStyle(ButtonStyle.Secondary),
|
||||||
.setStyle(ButtonStyle.Primary),
|
new ButtonBuilder().setCustomId("QueueEnd").setLabel("🔽").setStyle(ButtonStyle.Primary)
|
||||||
new ButtonBuilder()
|
|
||||||
.setCustomId("QueueUp")
|
|
||||||
.setLabel("🔺")
|
|
||||||
.setStyle(ButtonStyle.Secondary),
|
|
||||||
new ButtonBuilder()
|
|
||||||
.setCustomId("QueueDown")
|
|
||||||
.setLabel("🔻")
|
|
||||||
.setStyle(ButtonStyle.Secondary),
|
|
||||||
new ButtonBuilder()
|
|
||||||
.setCustomId("QueueEnd")
|
|
||||||
.setLabel("🔽")
|
|
||||||
.setStyle(ButtonStyle.Primary)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const message = (await ctx.editReply({
|
const message = (await ctx.editReply({
|
||||||
embeds: [I18n.en.queueDesigner(player.Queue, 0, player.Resource)],
|
embeds: [I18n.en.queueDesigner(player.Queue, 0, player.Resource)],
|
||||||
components: [row],
|
components: [row]
|
||||||
})) as Message;
|
})) as Message;
|
||||||
|
|
||||||
const collector = message.createMessageComponentCollector({ time: 30000 });
|
const collector = message.createMessageComponentCollector({ time: 30000 });
|
||||||
|
|
||||||
collector.on("collect", async (btn: ButtonInteraction) => {
|
collector.on("collect", async (btn: ButtonInteraction) => {
|
||||||
switch (btn.customId) {
|
switch (btn.customId) {
|
||||||
case "QueueTop": {
|
case "QueueTop": {
|
||||||
page = 0;
|
page = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "QueueUp": {
|
case "QueueUp": {
|
||||||
page = Math.max(page - 1, 0);
|
page = Math.max(page - 1, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "QueueDown": {
|
case "QueueDown": {
|
||||||
page = Math.min(page + 1, Math.floor(player.Queue.Tracks.length / 11));
|
page = Math.min(page + 1, Math.floor(player.Queue.Tracks.length / 11));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "QueueEnd":
|
case "QueueEnd":
|
||||||
page = Math.floor(player.Queue.Tracks.length / 11);
|
page = Math.floor(player.Queue.Tracks.length / 11);
|
||||||
}
|
}
|
||||||
|
|
||||||
await btn.update({
|
await btn.update({
|
||||||
embeds: [I18n.en.queueDesigner(player.Queue, page, player.Resource)],
|
embeds: [I18n.en.queueDesigner(player.Queue, page, player.Resource)]
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = new SlashCommandBuilder()
|
const data = new SlashCommandBuilder().setName("queue").setDescription("Print out the queue.");
|
||||||
.setName("queue")
|
|
||||||
.setDescription("Print out the queue.");
|
|
||||||
|
|
||||||
export { data };
|
export { data };
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import { CommandInteraction, SlashCommandBuilder, TextChannel } from "discord.js";
|
import { CommandInteraction, SlashCommandBuilder, TextChannel } from "discord.js";
|
||||||
import Client from "../lib/Client.js";
|
|
||||||
import I18n from "../lib/I18n.js";
|
import Client from "../lib/client.js";
|
||||||
|
import I18n from "../lib/i18n.js";
|
||||||
|
|
||||||
export async function run(client: Client, ctx: CommandInteraction) {
|
export async function run(client: Client, ctx: CommandInteraction) {
|
||||||
const query = ctx.options.get("query")?.value as string;
|
const query = ctx.options.get("query")?.value as string;
|
||||||
@@ -11,7 +12,10 @@ export async function run(client: Client, ctx: CommandInteraction) {
|
|||||||
|
|
||||||
if (!player) return;
|
if (!player) return;
|
||||||
|
|
||||||
const track = !isNaN(+query) && isFinite(+query) && !/e/i.test(query) ? player.remove(parseInt(query) - 1) : player.remove(query);
|
const track =
|
||||||
|
!isNaN(+query) && isFinite(+query) && !/e/i.test(query)
|
||||||
|
? player.remove(parseInt(query) - 1)
|
||||||
|
: player.remove(query);
|
||||||
|
|
||||||
await ctx.reply({ embeds: [I18n.en.removed(track)] });
|
await ctx.reply({ embeds: [I18n.en.removed(track)] });
|
||||||
}
|
}
|
||||||
@@ -19,10 +23,8 @@ export async function run(client: Client, ctx: CommandInteraction) {
|
|||||||
const data = new SlashCommandBuilder()
|
const data = new SlashCommandBuilder()
|
||||||
.setName("remove")
|
.setName("remove")
|
||||||
.setDescription("Remove specific track in the queue.")
|
.setDescription("Remove specific track in the queue.")
|
||||||
.addStringOption(option => option
|
.addStringOption((option) =>
|
||||||
.setName("query")
|
option.setName("query").setDescription("Position or title to remove.").setRequired(true)
|
||||||
.setDescription("Position or title to remove.")
|
|
||||||
.setRequired(true)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
export { data };
|
export { data };
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import { CommandInteraction, SlashCommandBuilder, TextChannel } from "discord.js";
|
import { CommandInteraction, SlashCommandBuilder, TextChannel } from "discord.js";
|
||||||
import Client from "../lib/Client.js";
|
|
||||||
import I18n from "../lib/I18n.js";
|
import Client from "../lib/client.js";
|
||||||
|
import I18n from "../lib/i18n.js";
|
||||||
|
|
||||||
export async function run(client: Client, ctx: CommandInteraction) {
|
export async function run(client: Client, ctx: CommandInteraction) {
|
||||||
if (!ctx.guild || !ctx.channel) return;
|
if (!ctx.guild || !ctx.channel) return;
|
||||||
@@ -14,8 +15,6 @@ export async function run(client: Client, ctx: CommandInteraction) {
|
|||||||
await ctx.reply({ embeds: [I18n.en.reshuffle()] });
|
await ctx.reply({ embeds: [I18n.en.reshuffle()] });
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = new SlashCommandBuilder()
|
const data = new SlashCommandBuilder().setName("reshuffle").setDescription("Shuffle the queue.");
|
||||||
.setName("reshuffle")
|
|
||||||
.setDescription("Shuffle the queue.");
|
|
||||||
|
|
||||||
export { data };
|
export { data };
|
||||||
+10
-18
@@ -1,11 +1,12 @@
|
|||||||
import { CommandInteraction, SlashCommandBuilder, TextChannel } from "discord.js";
|
import { CommandInteraction, SlashCommandBuilder, TextChannel } from "discord.js";
|
||||||
import Client from "../lib/Client.js";
|
|
||||||
import I18n from "../lib/I18n.js";
|
import Client from "../lib/client.js";
|
||||||
|
import I18n from "../lib/i18n.js";
|
||||||
|
|
||||||
export async function run(client: Client, ctx: CommandInteraction) {
|
export async function run(client: Client, ctx: CommandInteraction) {
|
||||||
const hours = ctx.options.get("hrs")?.value as number || 0;
|
const hours = (ctx.options.get("hrs")?.value as number) || 0;
|
||||||
const minutes = ctx.options.get("mins")?.value as number || 0;
|
const minutes = (ctx.options.get("mins")?.value as number) || 0;
|
||||||
const seconds = ctx.options.get("secs")?.value as number || 0;
|
const seconds = (ctx.options.get("secs")?.value as number) || 0;
|
||||||
|
|
||||||
if (!ctx.guild || !ctx.channel) return;
|
if (!ctx.guild || !ctx.channel) return;
|
||||||
|
|
||||||
@@ -18,24 +19,15 @@ export async function run(client: Client, ctx: CommandInteraction) {
|
|||||||
player.seek(time * 1000);
|
player.seek(time * 1000);
|
||||||
|
|
||||||
await ctx.reply({
|
await ctx.reply({
|
||||||
embeds: [I18n.en.fastForwarded(time)],
|
embeds: [I18n.en.fastForwarded(time)]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = new SlashCommandBuilder()
|
const data = new SlashCommandBuilder()
|
||||||
.setName("seek")
|
.setName("seek")
|
||||||
.setDescription("Fast-forward by the time.")
|
.setDescription("Fast-forward by the time.")
|
||||||
.addIntegerOption(option => option
|
.addIntegerOption((option) => option.setName("hrs").setDescription("Hours to seek."))
|
||||||
.setName("hrs")
|
.addIntegerOption((option) => option.setName("mins").setDescription("Minutes to seek."))
|
||||||
.setDescription("Hours to seek.")
|
.addIntegerOption((option) => option.setName("secs").setDescription("Seconds to seek."));
|
||||||
)
|
|
||||||
.addIntegerOption(option => option
|
|
||||||
.setName("mins")
|
|
||||||
.setDescription("Minutes to seek.")
|
|
||||||
)
|
|
||||||
.addIntegerOption(option => option
|
|
||||||
.setName("secs")
|
|
||||||
.setDescription("Seconds to seek.")
|
|
||||||
);
|
|
||||||
|
|
||||||
export { data };
|
export { data };
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import { CommandInteraction, SlashCommandBuilder, TextChannel } from "discord.js";
|
import { CommandInteraction, SlashCommandBuilder, TextChannel } from "discord.js";
|
||||||
import Client from "../lib/Client.js";
|
|
||||||
import I18n from "../lib/I18n.js";
|
import Client from "../lib/client.js";
|
||||||
|
import I18n from "../lib/i18n.js";
|
||||||
|
|
||||||
export async function run(client: Client, ctx: CommandInteraction) {
|
export async function run(client: Client, ctx: CommandInteraction) {
|
||||||
if (!ctx.guild || !ctx.channel) return;
|
if (!ctx.guild || !ctx.channel) return;
|
||||||
@@ -14,8 +15,6 @@ export async function run(client: Client, ctx: CommandInteraction) {
|
|||||||
await ctx.reply({ embeds: [I18n.en.destroyed()] });
|
await ctx.reply({ embeds: [I18n.en.destroyed()] });
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = new SlashCommandBuilder()
|
const data = new SlashCommandBuilder().setName("stop").setDescription("Destroy the player.");
|
||||||
.setName("stop")
|
|
||||||
.setDescription("Destroy the player.");
|
|
||||||
|
|
||||||
export { data };
|
export { data };
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
import { CommandInteraction, SlashCommandBuilder, TextChannel } from "discord.js";
|
import { CommandInteraction, SlashCommandBuilder, TextChannel } from "discord.js";
|
||||||
import Client from "../lib/Client.js";
|
|
||||||
import I18n from "../lib/I18n.js";
|
import Client from "../lib/client.js";
|
||||||
|
import I18n from "../lib/i18n.js";
|
||||||
|
|
||||||
export async function run(client: Client, ctx: CommandInteraction) {
|
export async function run(client: Client, ctx: CommandInteraction) {
|
||||||
const volume = ctx.options.get("volume")?.value as number || 100;
|
const volume = (ctx.options.get("volume")?.value as number) || 100;
|
||||||
|
|
||||||
if (!ctx.guild || !ctx.channel) return;
|
if (!ctx.guild || !ctx.channel) return;
|
||||||
|
|
||||||
@@ -19,10 +20,8 @@ export async function run(client: Client, ctx: CommandInteraction) {
|
|||||||
const data = new SlashCommandBuilder()
|
const data = new SlashCommandBuilder()
|
||||||
.setName("volume")
|
.setName("volume")
|
||||||
.setDescription("Change player's volume amount.")
|
.setDescription("Change player's volume amount.")
|
||||||
.addIntegerOption(option => option
|
.addIntegerOption((option) =>
|
||||||
.setName("volume")
|
option.setName("volume").setDescription("Volume in percents.").setRequired(true)
|
||||||
.setDescription("Volume in percents.")
|
|
||||||
.setRequired(true)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
export { data };
|
export { data };
|
||||||
+3
-1
@@ -4,7 +4,9 @@ import { fileURLToPath } from "url";
|
|||||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
token: process.env.DISCORD_TOKEN,
|
token:
|
||||||
|
process.env.DISCORD_TOKEN ??
|
||||||
|
"NzgzNDQwMjU3NjE3MzYyOTQ1.GQ0lLK.VftrGanpOtqfoKUQRkoXDCcbQqwMqBsybmwjGE",
|
||||||
commands: path.join(__dirname, "/commands/"),
|
commands: path.join(__dirname, "/commands/"),
|
||||||
events: path.join(__dirname, "/events/"),
|
events: path.join(__dirname, "/events/"),
|
||||||
binaries: path.join(__dirname, "/../bin/")
|
binaries: path.join(__dirname, "/../bin/")
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { Interaction } from "discord.js";
|
import { Interaction } from "discord.js";
|
||||||
import Client from "../lib/Client.js";
|
|
||||||
|
import Client from "../lib/client.js";
|
||||||
|
|
||||||
export async function run(client: Client, args: Interaction[]): Promise<void> {
|
export async function run(client: Client, args: Interaction[]): Promise<void> {
|
||||||
const [interaction] = args;
|
const [interaction] = args;
|
||||||
+3
-4
@@ -1,7 +1,8 @@
|
|||||||
import Client from "../lib/Client.js";
|
|
||||||
import { generateDependencyReport } from "@discordjs/voice";
|
import { generateDependencyReport } from "@discordjs/voice";
|
||||||
import { ActivityType } from "discord.js";
|
import { ActivityType } from "discord.js";
|
||||||
|
|
||||||
|
import Client from "../lib/client.js";
|
||||||
|
|
||||||
export async function run(client: Client): Promise<void> {
|
export async function run(client: Client): Promise<void> {
|
||||||
if (!client.user || !client.application) {
|
if (!client.user || !client.application) {
|
||||||
console.log("No user or application is provided!");
|
console.log("No user or application is provided!");
|
||||||
@@ -12,9 +13,7 @@ export async function run(client: Client): Promise<void> {
|
|||||||
console.log(generateDependencyReport());
|
console.log(generateDependencyReport());
|
||||||
client.user.setActivity("over you", { type: ActivityType.Watching });
|
client.user.setActivity("over you", { type: ActivityType.Watching });
|
||||||
|
|
||||||
const restCommands = Array.from(client.Commands.values()).map(
|
const restCommands = Array.from(client.Commands.values()).map((value) => value.data);
|
||||||
value => value.data
|
|
||||||
);
|
|
||||||
|
|
||||||
client.application.commands.set(restCommands);
|
client.application.commands.set(restCommands);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import { VoiceState } from "discord.js";
|
||||||
|
|
||||||
|
import Client from "../lib/client.js";
|
||||||
|
import I18n from "../lib/i18n.js";
|
||||||
|
import { asleep } from "../lib/misc.js";
|
||||||
|
|
||||||
|
export async function run(client: Client, args: VoiceState[]): Promise<void> {
|
||||||
|
const [oldState] = args;
|
||||||
|
|
||||||
|
const player = client.modules.music.get(oldState.guild.id);
|
||||||
|
|
||||||
|
if (!player || !oldState.channel || !client.user) return;
|
||||||
|
|
||||||
|
if (oldState.channel.members.filter((value) => value.user !== client.user).size === 0) {
|
||||||
|
await asleep(30000);
|
||||||
|
if (oldState.channel.members.filter((value) => value.user !== client.user).size === 0) {
|
||||||
|
await player.Channel.send({ embeds: [I18n.en.fullyAlone()] });
|
||||||
|
player.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const name = "voiceStateUpdate";
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
import { VoiceState } from "discord.js";
|
|
||||||
import I18n from "../lib/I18n.js";
|
|
||||||
import Client from "../lib/Client.js";
|
|
||||||
import { asleep } from "../lib/Misc.js";
|
|
||||||
|
|
||||||
export async function run(client: Client, args: VoiceState[]): Promise<void> {
|
|
||||||
const [oldState] = args;
|
|
||||||
|
|
||||||
const player = client.modules.music.get(oldState.guild.id);
|
|
||||||
|
|
||||||
if (!player || !oldState.channel || !client.user)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (oldState.channel.members.filter(value => value.user !== client.user).size === 0) {
|
|
||||||
await asleep(30000);
|
|
||||||
if (oldState.channel.members.filter(value => value.user !== client.user).size === 0) {
|
|
||||||
await player.Channel.send({ embeds: [I18n.en.fullyAlone()] });
|
|
||||||
player.destroy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export const name = "voiceStateUpdate";
|
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
import Client from "./lib/Client.js";
|
|
||||||
import config from "./config.js";
|
import config from "./config.js";
|
||||||
|
import Client from "./lib/client.js";
|
||||||
|
|
||||||
const client = new Client();
|
const client = new Client();
|
||||||
|
|
||||||
|
|||||||
-294
@@ -1,294 +0,0 @@
|
|||||||
import Player from "./Player.js";
|
|
||||||
import { loopOption, track } from "./Types.js";
|
|
||||||
import { loopMoji, secToISO, statusBarGenerator, volumeMoji } from "./Misc.js";
|
|
||||||
import Queue from "./Queue.js";
|
|
||||||
import { AudioResource } from "@discordjs/voice";
|
|
||||||
import { EmbedBuilder } from "discord.js";
|
|
||||||
|
|
||||||
export default class I18n {
|
|
||||||
public static en = {
|
|
||||||
nowPlaying: (track: track) => new EmbedBuilder()
|
|
||||||
.setColor("LuminousVividPink")
|
|
||||||
.setAuthor({
|
|
||||||
iconURL: track.requester.avatarURL() || undefined,
|
|
||||||
name: track.requester.tag,
|
|
||||||
})
|
|
||||||
.setTitle(track.title)
|
|
||||||
.setURL(track.url)
|
|
||||||
.setDescription("**playing now.**")
|
|
||||||
.setThumbnail(track.thumbnail),
|
|
||||||
cleared: (amount: number) => new EmbedBuilder()
|
|
||||||
.setColor("Green")
|
|
||||||
.setTitle(
|
|
||||||
`**♻️ ${amount} tracks have been cleared from the queue.**`
|
|
||||||
)
|
|
||||||
.setTimestamp(new Date()),
|
|
||||||
okConnected: (channel: string) => new EmbedBuilder()
|
|
||||||
.setColor("Green")
|
|
||||||
.setTitle(`**✅ Successfuly connected to:** _${channel}_.`),
|
|
||||||
notConnected: () => new EmbedBuilder()
|
|
||||||
.setColor("Red")
|
|
||||||
.setTitle(
|
|
||||||
"**🚫 Make yourself connected to a voice channel beforehand.**"
|
|
||||||
),
|
|
||||||
wasConnected: () => new EmbedBuilder()
|
|
||||||
.setColor("Yellow")
|
|
||||||
.setTitle("**⚠️ Already connected to a voice channel.**"),
|
|
||||||
filtered: (filter?: string) => new EmbedBuilder()
|
|
||||||
.setColor("Green")
|
|
||||||
.setTitle(filter ? `**✅ ${filter} was applied to the player.**` : "**✅ All filters were declined.**"),
|
|
||||||
appended: (track?: track) => !track
|
|
||||||
? new EmbedBuilder()
|
|
||||||
.setColor("Red")
|
|
||||||
.setTitle("**🚫 Could not add track to the queue.**")
|
|
||||||
: new EmbedBuilder()
|
|
||||||
.setColor("Green")
|
|
||||||
.setTitle(track.title)
|
|
||||||
.setURL(track.url)
|
|
||||||
.setThumbnail(track.thumbnail)
|
|
||||||
.setAuthor({
|
|
||||||
iconURL: track.requester.avatarURL() || undefined,
|
|
||||||
name: track.requester.tag,
|
|
||||||
})
|
|
||||||
.setDescription("**has been added to the queue.**")
|
|
||||||
.setTimestamp(new Date()),
|
|
||||||
jumped: (state: boolean) => state
|
|
||||||
? new EmbedBuilder()
|
|
||||||
.setColor("Green")
|
|
||||||
.setTitle("_**Perfoming jump.**_")
|
|
||||||
: new EmbedBuilder()
|
|
||||||
.setColor("Red")
|
|
||||||
.setTitle("**❗ Bad _jump_ request.**"),
|
|
||||||
looped: (query: loopOption) => {
|
|
||||||
switch (query) {
|
|
||||||
case "AUTO": {
|
|
||||||
return new EmbedBuilder()
|
|
||||||
.setColor("LuminousVividPink")
|
|
||||||
.setTitle(
|
|
||||||
"**🔀 Shuffle mode** _(does not affect the queue order)_."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
case "LOOP": {
|
|
||||||
return new EmbedBuilder()
|
|
||||||
.setColor("Blue")
|
|
||||||
.setTitle("**🔁 Looping over the queue.**");
|
|
||||||
}
|
|
||||||
case "NONE": {
|
|
||||||
return new EmbedBuilder()
|
|
||||||
.setColor("Red")
|
|
||||||
.setTitle("**⤵️ Player will stop on the queue end.**");
|
|
||||||
}
|
|
||||||
case "SONG": {
|
|
||||||
return new EmbedBuilder()
|
|
||||||
.setColor("Yellow")
|
|
||||||
.setTitle("**🔂 Looping a single track.**");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
skipped: () => new EmbedBuilder()
|
|
||||||
.setColor("Green")
|
|
||||||
.setTitle("**⏭️ Skipping.**"),
|
|
||||||
paused: (state: boolean) => state
|
|
||||||
? new EmbedBuilder()
|
|
||||||
.setColor("Green")
|
|
||||||
.setTitle("_**▶️ Resumed.**_")
|
|
||||||
: new EmbedBuilder()
|
|
||||||
.setColor("Yellow")
|
|
||||||
.setTitle("_**⏸️ Paused.**_"),
|
|
||||||
removed: (track?: track) => track
|
|
||||||
? new EmbedBuilder()
|
|
||||||
.setColor("Green")
|
|
||||||
.setTitle(track.title)
|
|
||||||
.setDescription("**was removed from the queue.**")
|
|
||||||
.setTimestamp(new Date())
|
|
||||||
.setURL(track.url)
|
|
||||||
.setThumbnail(track.thumbnail)
|
|
||||||
: new EmbedBuilder()
|
|
||||||
.setColor("Red")
|
|
||||||
.setTitle("**❗ Bad _remove_ request.**"),
|
|
||||||
fastForwarded: (amount: number) => new EmbedBuilder()
|
|
||||||
.setColor("Blue")
|
|
||||||
.setTitle(
|
|
||||||
`**⏩ Fast-forwarding to ${secToISO(
|
|
||||||
amount
|
|
||||||
)}**`
|
|
||||||
),
|
|
||||||
destroyed: () => new EmbedBuilder()
|
|
||||||
.setColor("Red")
|
|
||||||
.setTitle("**💀 Destroying the player.**"),
|
|
||||||
volumeSet: (amount: number) => new EmbedBuilder()
|
|
||||||
.setColor("Green")
|
|
||||||
.setTitle(`**${volumeMoji(amount)} Volume has been set to ${amount}%**`),
|
|
||||||
queueEmpty: () => new EmbedBuilder()
|
|
||||||
.setColor("Yellow")
|
|
||||||
.setTitle("**❎ Queue is empty.**"),
|
|
||||||
playerInfo: (player?: Player) => {
|
|
||||||
if (!player)
|
|
||||||
return new EmbedBuilder()
|
|
||||||
.setColor("Red")
|
|
||||||
.setTitle("**🚫 Player does not exist.**");
|
|
||||||
|
|
||||||
if (player.Resource) {
|
|
||||||
return new EmbedBuilder()
|
|
||||||
.setColor("LuminousVividPink")
|
|
||||||
.setTitle(
|
|
||||||
`${player.Queue.Position + 1}. ${player.Resource.metadata.title}`
|
|
||||||
)
|
|
||||||
.setDescription(
|
|
||||||
statusBarGenerator(
|
|
||||||
player.Resource.playbackDuration / 1000,
|
|
||||||
player.Resource.metadata.duration
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.setThumbnail(player.Resource.metadata.thumbnail)
|
|
||||||
.setURL(player.Resource.metadata.url)
|
|
||||||
.addFields([
|
|
||||||
{
|
|
||||||
name: "Applied Filters",
|
|
||||||
value:
|
|
||||||
player.Filter.Filters.map(
|
|
||||||
(value) => value[0]
|
|
||||||
).join("\n") + "\ndefault",
|
|
||||||
inline: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Queue Length",
|
|
||||||
value: `🔢 ${player.Queue.Tracks.length}`,
|
|
||||||
inline: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Queue Duration",
|
|
||||||
value: `💿 ${secToISO(player.Queue.Duration)}`,
|
|
||||||
inline: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Queue Looping",
|
|
||||||
value: `${loopMoji(player.Queue.Loop)} ${player.Queue.Loop}`,
|
|
||||||
inline: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Volume amount",
|
|
||||||
value: `${volumeMoji(player.Volume)} ${player.Volume}/150`,
|
|
||||||
inline: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Player lifetime",
|
|
||||||
value: `🕓 ${secToISO((Date.now() - player.Created.getTime()) / 1000)}`,
|
|
||||||
inline: true,
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return new EmbedBuilder()
|
|
||||||
.setColor("Blue")
|
|
||||||
.setTitle("💿 Insert the disk...")
|
|
||||||
.setDescription(statusBarGenerator(0, 0))
|
|
||||||
.setURL(
|
|
||||||
"https://www.youtube.com/watch?v=dQw4w9WgXcQ&ab_channel=RickAstley"
|
|
||||||
)
|
|
||||||
.addFields([
|
|
||||||
{
|
|
||||||
name: "Applied Filters",
|
|
||||||
value:
|
|
||||||
player.Filter.Filters.map(
|
|
||||||
(value) => value[0]
|
|
||||||
).join("\n") + "\ndefault",
|
|
||||||
inline: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Queue Length",
|
|
||||||
value: `🔢 ${player.Queue.Tracks.length}`,
|
|
||||||
inline: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Queue Duration",
|
|
||||||
value: `💿 ${secToISO(player.Queue.Duration)}`,
|
|
||||||
inline: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Queue Looping",
|
|
||||||
value: `${loopMoji(player.Queue.Loop)} ${player.Queue.Loop}`,
|
|
||||||
inline: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Volume amount",
|
|
||||||
value: `${volumeMoji(player.Volume)} ${player.Volume}/150`,
|
|
||||||
inline: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Player lifetime",
|
|
||||||
value: `🕓 ${secToISO((Date.now() - player.Created.getTime()) / 1000)}`,
|
|
||||||
inline: true,
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
queueDesigner: (
|
|
||||||
queue: Queue,
|
|
||||||
page: number,
|
|
||||||
resource: AudioResource<track> | undefined
|
|
||||||
) => {
|
|
||||||
page = Math.max(
|
|
||||||
0,
|
|
||||||
Math.min(Math.floor(queue.Tracks.length / 11), page)
|
|
||||||
);
|
|
||||||
|
|
||||||
return new EmbedBuilder()
|
|
||||||
.setColor("LuminousVividPink")
|
|
||||||
.setTitle(
|
|
||||||
resource
|
|
||||||
? `${queue.Position + 1}. ${resource.metadata.title}`
|
|
||||||
: "💿 Insert the disk..."
|
|
||||||
)
|
|
||||||
.setURL(
|
|
||||||
resource
|
|
||||||
? resource.metadata.url
|
|
||||||
: "https://www.youtube.com/watch?v=5mGuCdlCcNM&ab_channel=Ra%C3%BAlBlanco"
|
|
||||||
)
|
|
||||||
.setThumbnail(
|
|
||||||
resource
|
|
||||||
? resource.metadata.thumbnail
|
|
||||||
: "https/img.youtube.com/vi/5mGuCdlCcNM/default.jpg"
|
|
||||||
)
|
|
||||||
.setDescription(
|
|
||||||
resource
|
|
||||||
? statusBarGenerator(
|
|
||||||
resource.playbackDuration / 1000,
|
|
||||||
resource.metadata.duration
|
|
||||||
)
|
|
||||||
: statusBarGenerator(0, 0)
|
|
||||||
)
|
|
||||||
.setFields(
|
|
||||||
queue.Tracks.slice(page * 10, page * 10 + 10).map(
|
|
||||||
(value, index) => ({
|
|
||||||
name: `${
|
|
||||||
page * 10 + index + 1
|
|
||||||
}. ${value.title.padEnd(35)}`,
|
|
||||||
value: `**[${secToISO(value.duration)}]**`,
|
|
||||||
})
|
|
||||||
)
|
|
||||||
);
|
|
||||||
},
|
|
||||||
fullyAlone: () => new EmbedBuilder()
|
|
||||||
.setColor("LuminousVividPink")
|
|
||||||
.setTitle("🥬 I have decided to leave to conserve my energy.")
|
|
||||||
.setDescription(
|
|
||||||
"_**Since there was nobody in the voice channel.**_"
|
|
||||||
),
|
|
||||||
reshuffle: () => new EmbedBuilder()
|
|
||||||
.setColor("Green")
|
|
||||||
.setTitle("**✅ Successfuly reshuffled queue.**"),
|
|
||||||
ping: (ping?: number) => {
|
|
||||||
const title = ping ? `I have pinged ${ping} ms late.` : "There is no application.";
|
|
||||||
|
|
||||||
const comment = !ping ? "How am I speaking then?" : ping > 250 ? "I'm kinda slowpoke ngl." :
|
|
||||||
ping > 200 ? "I can do better than this." :
|
|
||||||
"Dream's speed!";
|
|
||||||
|
|
||||||
return new EmbedBuilder()
|
|
||||||
.setColor("Random")
|
|
||||||
.setTitle(`**${title}**`)
|
|
||||||
.setDescription(`_**${comment}**_`);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,14 +1,12 @@
|
|||||||
import {
|
import { Client as DiscordClient, GatewayIntentBits } from "discord.js";
|
||||||
Client as DiscordClient,
|
|
||||||
GatewayIntentBits
|
|
||||||
} from "discord.js";
|
|
||||||
import { existsSync, readdirSync } from "fs";
|
import { existsSync, readdirSync } from "fs";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import Music from "./Music.js";
|
|
||||||
import { command, event } from "./Types.js";
|
|
||||||
import config from "../config.js";
|
|
||||||
import { pathToFileURL } from "url";
|
import { pathToFileURL } from "url";
|
||||||
|
|
||||||
|
import config from "../config.js";
|
||||||
|
import Music from "./music.js";
|
||||||
|
import { command, event } from "./types.js";
|
||||||
|
|
||||||
export default class Client extends DiscordClient {
|
export default class Client extends DiscordClient {
|
||||||
private commands = new Map<string, command>();
|
private commands = new Map<string, command>();
|
||||||
|
|
||||||
@@ -22,35 +20,28 @@ export default class Client extends DiscordClient {
|
|||||||
|
|
||||||
public constructor() {
|
public constructor() {
|
||||||
super({
|
super({
|
||||||
intents: [
|
intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildVoiceStates]
|
||||||
GatewayIntentBits.Guilds,
|
|
||||||
GatewayIntentBits.GuildVoiceStates
|
|
||||||
],
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (existsSync(config.commands)) {
|
if (existsSync(config.commands)) {
|
||||||
const files = readdirSync(config.commands).filter((file) =>
|
const files = readdirSync(config.commands).filter((file) => file.endsWith(".js"));
|
||||||
file.endsWith(".js")
|
|
||||||
);
|
|
||||||
|
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
import(pathToFileURL(path.join(config.commands, file)).toString()).then((cmd: command) =>
|
import(pathToFileURL(path.join(config.commands, file)).toString()).then(
|
||||||
this.commands.set(cmd.data.name, cmd)
|
(cmd: command) => this.commands.set(cmd.data.name, cmd)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (existsSync(config.events)) {
|
if (existsSync(config.events)) {
|
||||||
const files = readdirSync(config.events).filter((file) =>
|
const files = readdirSync(config.events).filter((file) => file.endsWith(".js"));
|
||||||
file.endsWith(".js")
|
|
||||||
);
|
|
||||||
|
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
import(pathToFileURL(path.join(config.events, file)).toString()).then((evnt: event) => {
|
import(pathToFileURL(path.join(config.events, file)).toString()).then(
|
||||||
this.on(evnt.name, (...args: unknown[]) =>
|
(evnt: event) => {
|
||||||
evnt.run(this, args)
|
this.on(evnt.name, (...args: unknown[]) => evnt.run(this, args));
|
||||||
);
|
}
|
||||||
});
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
import { ytdlArgs, ytdlResponse } from "./Types.js";
|
|
||||||
import { execFile } from "child_process";
|
import { execFile } from "child_process";
|
||||||
import { promisify } from "util";
|
|
||||||
import config from "../config.js";
|
|
||||||
import path from "path";
|
import path from "path";
|
||||||
|
import { promisify } from "util";
|
||||||
|
|
||||||
|
import config from "../config.js";
|
||||||
|
import { ytdlArgs, ytdlResponse } from "./types.js";
|
||||||
|
|
||||||
const execFileAsync = promisify(execFile);
|
const execFileAsync = promisify(execFile);
|
||||||
|
|
||||||
@@ -11,27 +12,20 @@ function argumentsResolver(args: ytdlArgs): string[] {
|
|||||||
return options.map(([key, value]) => {
|
return options.map(([key, value]) => {
|
||||||
if (typeof value === "boolean" && value) {
|
if (typeof value === "boolean" && value) {
|
||||||
return `--${key.split(/(?=[A-Z])/).join("-")}`.toLowerCase();
|
return `--${key.split(/(?=[A-Z])/).join("-")}`.toLowerCase();
|
||||||
}
|
} else {
|
||||||
else {
|
return `--${key.split(/(?=[A-Z])/).join("-")}=${value}`.toLowerCase();
|
||||||
return `--${key
|
|
||||||
.split(/(?=[A-Z])/)
|
|
||||||
.join("-")}=${value}`.toLowerCase();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function ytdlExec(
|
async function ytdlExec(query: string, args: ytdlArgs): Promise<ytdlResponse | undefined> {
|
||||||
query: string,
|
|
||||||
args: ytdlArgs
|
|
||||||
): Promise<ytdlResponse | undefined> {
|
|
||||||
try {
|
try {
|
||||||
const executable = await execFileAsync(
|
const executable = await execFileAsync(
|
||||||
path.join(config.binaries, "/youtube-dl"),
|
path.join(config.binaries, "/youtube-dl"),
|
||||||
[query].concat(argumentsResolver(args))
|
[query].concat(argumentsResolver(args))
|
||||||
);
|
);
|
||||||
return JSON.parse(executable.stdout);
|
return JSON.parse(executable.stdout);
|
||||||
}
|
} catch (error) {
|
||||||
catch (error) {
|
|
||||||
console.log(error);
|
console.log(error);
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
@@ -44,11 +38,8 @@ export async function fetchStream(
|
|||||||
let response = await ytdlExec(query, args);
|
let response = await ytdlExec(query, args);
|
||||||
|
|
||||||
if (response && !response.extractor.includes("youtube")) {
|
if (response && !response.extractor.includes("youtube")) {
|
||||||
response = await ytdlExec(
|
response = await ytdlExec(`${response.title} - ${response.creator}`, args);
|
||||||
`${response.title} - ${response.creator}`,
|
|
||||||
args
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
@@ -24,35 +24,27 @@ export default class Filter {
|
|||||||
mono: [false, "pan=mono|c0=.5*c0+.5*c1"],
|
mono: [false, "pan=mono|c0=.5*c0+.5*c1"],
|
||||||
mstlr: [false, "stereotools=mode=ms>lr"],
|
mstlr: [false, "stereotools=mode=ms>lr"],
|
||||||
mstrr: [false, "stereotools=mode=ms>rr"],
|
mstrr: [false, "stereotools=mode=ms>rr"],
|
||||||
compressor: [
|
compressor: [false, "compand=points=-80/-105|-62/-80|-15.4/-15.4|0/-12|20/-7.6"],
|
||||||
false,
|
|
||||||
"compand=points=-80/-105|-62/-80|-15.4/-15.4|0/-12|20/-7.6",
|
|
||||||
],
|
|
||||||
expander: [
|
expander: [
|
||||||
false,
|
false,
|
||||||
"compand=attacks=0:points=-80/-169|-54/-80|-49.5/-64.6|-41.1/-41.1|-25.8/-15|-10.8/-4.5|0/0|20/8.3",
|
"compand=attacks=0:points=-80/-169|-54/-80|-49.5/-64.6|-41.1/-41.1|-25.8/-15|-10.8/-4.5|0/0|20/8.3"
|
||||||
],
|
|
||||||
softlimiter: [
|
|
||||||
false,
|
|
||||||
"compand=attacks=0:points=-80/-80|-12.4/-12.4|-6/-8|0/-6.8|20/-2.8",
|
|
||||||
],
|
],
|
||||||
|
softlimiter: [false, "compand=attacks=0:points=-80/-80|-12.4/-12.4|-6/-8|0/-6.8|20/-2.8"],
|
||||||
chorus: [false, "chorus=0.7:0.9:55:0.4:0.25:2"],
|
chorus: [false, "chorus=0.7:0.9:55:0.4:0.25:2"],
|
||||||
chorus2d: [false, "chorus=0.6:0.9:50|60:0.4|0.32:0.25|0.4:2|1.3"],
|
chorus2d: [false, "chorus=0.6:0.9:50|60:0.4|0.32:0.25|0.4:2|1.3"],
|
||||||
chorus3d: [
|
chorus3d: [false, "chorus=0.5:0.9:50|60|40:0.4|0.32|0.3:0.25|0.4|0.3:2|2.3|1.3"],
|
||||||
false,
|
|
||||||
"chorus=0.5:0.9:50|60|40:0.4|0.32|0.3:0.25|0.4|0.3:2|2.3|1.3",
|
|
||||||
],
|
|
||||||
fadein: [false, "afade=t=in:ss=0:d=10"],
|
fadein: [false, "afade=t=in:ss=0:d=10"],
|
||||||
dim: [
|
dim: [
|
||||||
false,
|
false,
|
||||||
"afftfilt=\"'real=re * (1-clip((b/nb)*b,0,1))':imag='im * (1-clip((b/nb)*b,0,1))'\"",
|
"afftfilt=\"'real=re * (1-clip((b/nb)*b,0,1))':imag='im * (1-clip((b/nb)*b,0,1))'\""
|
||||||
],
|
],
|
||||||
earrape: [false, "channelsplit,sidechaingate=level_in=64"],
|
earrape: [false, "channelsplit,sidechaingate=level_in=64"]
|
||||||
};
|
};
|
||||||
|
|
||||||
public get Filters(): [string, string][] {
|
public get Filters(): [string, string][] {
|
||||||
return Object.entries(this.filters)
|
return Object.entries(this.filters)
|
||||||
.filter(value => value[1][0]).map(value => [value[0], value[1][1]]);
|
.filter((value) => value[1][0])
|
||||||
|
.map((value) => [value[0], value[1][1]]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public toggle(filter?: string): void {
|
public toggle(filter?: string): void {
|
||||||
@@ -68,7 +60,7 @@ export default class Filter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public toString(): string {
|
public toString(): string {
|
||||||
return this.Filters.map(value => value[1]).join(",");
|
return this.Filters.map((value) => value[1]).join(",");
|
||||||
}
|
}
|
||||||
|
|
||||||
public empty(): boolean {
|
public empty(): boolean {
|
||||||
+270
@@ -0,0 +1,270 @@
|
|||||||
|
import { AudioResource } from "@discordjs/voice";
|
||||||
|
import { EmbedBuilder } from "discord.js";
|
||||||
|
|
||||||
|
import { loopMoji, secToISO, statusBarGenerator, volumeMoji } from "./misc.js";
|
||||||
|
import Player from "./player.js";
|
||||||
|
import Queue from "./queue.js";
|
||||||
|
import { loopOption, track } from "./types.js";
|
||||||
|
|
||||||
|
export default class I18n {
|
||||||
|
public static en = {
|
||||||
|
nowPlaying: (track: track) =>
|
||||||
|
new EmbedBuilder()
|
||||||
|
.setColor("LuminousVividPink")
|
||||||
|
.setAuthor({
|
||||||
|
iconURL: track.requester.avatarURL() || undefined,
|
||||||
|
name: track.requester.tag
|
||||||
|
})
|
||||||
|
.setTitle(track.title)
|
||||||
|
.setURL(track.url)
|
||||||
|
.setDescription("**playing now.**")
|
||||||
|
.setThumbnail(track.thumbnail),
|
||||||
|
cleared: (amount: number) =>
|
||||||
|
new EmbedBuilder()
|
||||||
|
.setColor("Green")
|
||||||
|
.setTitle(`**♻️ ${amount} tracks have been cleared from the queue.**`)
|
||||||
|
.setTimestamp(new Date()),
|
||||||
|
okConnected: (channel: string) =>
|
||||||
|
new EmbedBuilder()
|
||||||
|
.setColor("Green")
|
||||||
|
.setTitle(`**✅ Successfuly connected to:** _${channel}_.`),
|
||||||
|
notConnected: () =>
|
||||||
|
new EmbedBuilder()
|
||||||
|
.setColor("Red")
|
||||||
|
.setTitle("**🚫 Make yourself connected to a voice channel beforehand.**"),
|
||||||
|
wasConnected: () =>
|
||||||
|
new EmbedBuilder()
|
||||||
|
.setColor("Yellow")
|
||||||
|
.setTitle("**⚠️ Already connected to a voice channel.**"),
|
||||||
|
filtered: (filter?: string) =>
|
||||||
|
new EmbedBuilder()
|
||||||
|
.setColor("Green")
|
||||||
|
.setTitle(
|
||||||
|
filter
|
||||||
|
? `**✅ ${filter} was applied to the player.**`
|
||||||
|
: "**✅ All filters were declined.**"
|
||||||
|
),
|
||||||
|
appended: (track?: track) =>
|
||||||
|
!track
|
||||||
|
? new EmbedBuilder()
|
||||||
|
.setColor("Red")
|
||||||
|
.setTitle("**🚫 Could not add track to the queue.**")
|
||||||
|
: new EmbedBuilder()
|
||||||
|
.setColor("Green")
|
||||||
|
.setTitle(track.title)
|
||||||
|
.setURL(track.url)
|
||||||
|
.setThumbnail(track.thumbnail)
|
||||||
|
.setAuthor({
|
||||||
|
iconURL: track.requester.avatarURL() || undefined,
|
||||||
|
name: track.requester.tag
|
||||||
|
})
|
||||||
|
.setDescription("**has been added to the queue.**")
|
||||||
|
.setTimestamp(new Date()),
|
||||||
|
jumped: (state: boolean) =>
|
||||||
|
state
|
||||||
|
? new EmbedBuilder().setColor("Green").setTitle("_**Perfoming jump.**_")
|
||||||
|
: new EmbedBuilder().setColor("Red").setTitle("**❗ Bad _jump_ request.**"),
|
||||||
|
looped: (query: loopOption) => {
|
||||||
|
switch (query) {
|
||||||
|
case "AUTO": {
|
||||||
|
return new EmbedBuilder()
|
||||||
|
.setColor("LuminousVividPink")
|
||||||
|
.setTitle("**🔀 Shuffle mode** _(does not affect the queue order)_.");
|
||||||
|
}
|
||||||
|
case "LOOP": {
|
||||||
|
return new EmbedBuilder()
|
||||||
|
.setColor("Blue")
|
||||||
|
.setTitle("**🔁 Looping over the queue.**");
|
||||||
|
}
|
||||||
|
case "NONE": {
|
||||||
|
return new EmbedBuilder()
|
||||||
|
.setColor("Red")
|
||||||
|
.setTitle("**⤵️ Player will stop on the queue end.**");
|
||||||
|
}
|
||||||
|
case "SONG": {
|
||||||
|
return new EmbedBuilder()
|
||||||
|
.setColor("Yellow")
|
||||||
|
.setTitle("**🔂 Looping a single track.**");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
skipped: () => new EmbedBuilder().setColor("Green").setTitle("**⏭️ Skipping.**"),
|
||||||
|
paused: (state: boolean) =>
|
||||||
|
state
|
||||||
|
? new EmbedBuilder().setColor("Green").setTitle("_**▶️ Resumed.**_")
|
||||||
|
: new EmbedBuilder().setColor("Yellow").setTitle("_**⏸️ Paused.**_"),
|
||||||
|
removed: (track?: track) =>
|
||||||
|
track
|
||||||
|
? new EmbedBuilder()
|
||||||
|
.setColor("Green")
|
||||||
|
.setTitle(track.title)
|
||||||
|
.setDescription("**was removed from the queue.**")
|
||||||
|
.setTimestamp(new Date())
|
||||||
|
.setURL(track.url)
|
||||||
|
.setThumbnail(track.thumbnail)
|
||||||
|
: new EmbedBuilder().setColor("Red").setTitle("**❗ Bad _remove_ request.**"),
|
||||||
|
fastForwarded: (amount: number) =>
|
||||||
|
new EmbedBuilder()
|
||||||
|
.setColor("Blue")
|
||||||
|
.setTitle(`**⏩ Fast-forwarding to ${secToISO(amount)}**`),
|
||||||
|
destroyed: () =>
|
||||||
|
new EmbedBuilder().setColor("Red").setTitle("**💀 Destroying the player.**"),
|
||||||
|
volumeSet: (amount: number) =>
|
||||||
|
new EmbedBuilder()
|
||||||
|
.setColor("Green")
|
||||||
|
.setTitle(`**${volumeMoji(amount)} Volume has been set to ${amount}%**`),
|
||||||
|
queueEmpty: () => new EmbedBuilder().setColor("Yellow").setTitle("**❎ Queue is empty.**"),
|
||||||
|
playerInfo: (player?: Player) => {
|
||||||
|
if (!player)
|
||||||
|
return new EmbedBuilder()
|
||||||
|
.setColor("Red")
|
||||||
|
.setTitle("**🚫 Player does not exist.**");
|
||||||
|
|
||||||
|
if (player.Resource) {
|
||||||
|
return new EmbedBuilder()
|
||||||
|
.setColor("LuminousVividPink")
|
||||||
|
.setTitle(`${player.Queue.Position + 1}. ${player.Resource.metadata.title}`)
|
||||||
|
.setDescription(
|
||||||
|
statusBarGenerator(
|
||||||
|
player.Resource.playbackDuration / 1000,
|
||||||
|
player.Resource.metadata.duration
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.setThumbnail(player.Resource.metadata.thumbnail)
|
||||||
|
.setURL(player.Resource.metadata.url)
|
||||||
|
.addFields([
|
||||||
|
{
|
||||||
|
name: "Applied Filters",
|
||||||
|
value:
|
||||||
|
player.Filter.Filters.map((value) => value[0]).join("\n") +
|
||||||
|
"\ndefault",
|
||||||
|
inline: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Queue Length",
|
||||||
|
value: `🔢 ${player.Queue.Tracks.length}`,
|
||||||
|
inline: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Queue Duration",
|
||||||
|
value: `💿 ${secToISO(player.Queue.Duration)}`,
|
||||||
|
inline: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Queue Looping",
|
||||||
|
value: `${loopMoji(player.Queue.Loop)} ${player.Queue.Loop}`,
|
||||||
|
inline: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Volume amount",
|
||||||
|
value: `${volumeMoji(player.Volume)} ${player.Volume}/150`,
|
||||||
|
inline: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Player lifetime",
|
||||||
|
value: `🕓 ${secToISO((Date.now() - player.Created.getTime()) / 1000)}`,
|
||||||
|
inline: true
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
return new EmbedBuilder()
|
||||||
|
.setColor("Blue")
|
||||||
|
.setTitle("💿 Insert the disk...")
|
||||||
|
.setDescription(statusBarGenerator(0, 0))
|
||||||
|
.setURL("https://www.youtube.com/watch?v=dQw4w9WgXcQ&ab_channel=RickAstley")
|
||||||
|
.addFields([
|
||||||
|
{
|
||||||
|
name: "Applied Filters",
|
||||||
|
value:
|
||||||
|
player.Filter.Filters.map((value) => value[0]).join("\n") +
|
||||||
|
"\ndefault",
|
||||||
|
inline: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Queue Length",
|
||||||
|
value: `🔢 ${player.Queue.Tracks.length}`,
|
||||||
|
inline: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Queue Duration",
|
||||||
|
value: `💿 ${secToISO(player.Queue.Duration)}`,
|
||||||
|
inline: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Queue Looping",
|
||||||
|
value: `${loopMoji(player.Queue.Loop)} ${player.Queue.Loop}`,
|
||||||
|
inline: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Volume amount",
|
||||||
|
value: `${volumeMoji(player.Volume)} ${player.Volume}/150`,
|
||||||
|
inline: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Player lifetime",
|
||||||
|
value: `🕓 ${secToISO((Date.now() - player.Created.getTime()) / 1000)}`,
|
||||||
|
inline: true
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
queueDesigner: (queue: Queue, page: number, resource: AudioResource<track> | undefined) => {
|
||||||
|
page = Math.max(0, Math.min(Math.floor(queue.Tracks.length / 11), page));
|
||||||
|
|
||||||
|
return new EmbedBuilder()
|
||||||
|
.setColor("LuminousVividPink")
|
||||||
|
.setTitle(
|
||||||
|
resource
|
||||||
|
? `${queue.Position + 1}. ${resource.metadata.title}`
|
||||||
|
: "💿 Insert the disk..."
|
||||||
|
)
|
||||||
|
.setURL(
|
||||||
|
resource
|
||||||
|
? resource.metadata.url
|
||||||
|
: "https://www.youtube.com/watch?v=5mGuCdlCcNM&ab_channel=Ra%C3%BAlBlanco"
|
||||||
|
)
|
||||||
|
.setThumbnail(
|
||||||
|
resource
|
||||||
|
? resource.metadata.thumbnail
|
||||||
|
: "https/img.youtube.com/vi/5mGuCdlCcNM/default.jpg"
|
||||||
|
)
|
||||||
|
.setDescription(
|
||||||
|
resource
|
||||||
|
? statusBarGenerator(
|
||||||
|
resource.playbackDuration / 1000,
|
||||||
|
resource.metadata.duration
|
||||||
|
)
|
||||||
|
: statusBarGenerator(0, 0)
|
||||||
|
)
|
||||||
|
.setFields(
|
||||||
|
queue.Tracks.slice(page * 10, page * 10 + 10).map((value, index) => ({
|
||||||
|
name: `${page * 10 + index + 1}. ${value.title.padEnd(35)}`,
|
||||||
|
value: `**[${secToISO(value.duration)}]**`
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
},
|
||||||
|
fullyAlone: () =>
|
||||||
|
new EmbedBuilder()
|
||||||
|
.setColor("LuminousVividPink")
|
||||||
|
.setTitle("🥬 I have decided to leave to conserve my energy.")
|
||||||
|
.setDescription("_**Since there was nobody in the voice channel.**_"),
|
||||||
|
reshuffle: () =>
|
||||||
|
new EmbedBuilder().setColor("Green").setTitle("**✅ Successfuly reshuffled queue.**"),
|
||||||
|
ping: (ping?: number) => {
|
||||||
|
const title = ping ? `I have pinged ${ping} ms late.` : "There is no application.";
|
||||||
|
|
||||||
|
const comment = !ping
|
||||||
|
? "How am I speaking then?"
|
||||||
|
: ping > 250
|
||||||
|
? "I'm kinda slowpoke ngl."
|
||||||
|
: ping > 200
|
||||||
|
? "I can do better than this."
|
||||||
|
: "Dream's speed!";
|
||||||
|
|
||||||
|
return new EmbedBuilder()
|
||||||
|
.setColor("Random")
|
||||||
|
.setTitle(`**${title}**`)
|
||||||
|
.setDescription(`_**${comment}**_`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,19 +1,17 @@
|
|||||||
import { loopOption } from "./Types.js";
|
import { loopOption } from "./types.js";
|
||||||
|
|
||||||
export function statusBarGenerator(duration: number, length: number): string {
|
export function statusBarGenerator(duration: number, length: number): string {
|
||||||
duration = Math.max(0, duration);
|
duration = Math.max(0, duration);
|
||||||
length = Math.max(0, length);
|
length = Math.max(0, length);
|
||||||
if (duration > length) duration = length;
|
if (duration > length) duration = length;
|
||||||
const filled = Array<string>(
|
const filled = Array<string>(Math.floor((15 * duration) / (length === 0 ? 1 : length))).fill(
|
||||||
Math.floor((15 * duration) / (length === 0 ? 1 : length))
|
":small_blue_diamond:"
|
||||||
).fill(":small_blue_diamond:");
|
);
|
||||||
const empty = Array<string>(
|
const empty = Array<string>(
|
||||||
15 - Math.floor((15 * duration) / (length === 0 ? 1 : length))
|
15 - Math.floor((15 * duration) / (length === 0 ? 1 : length))
|
||||||
).fill(":white_small_square:");
|
).fill(":white_small_square:");
|
||||||
|
|
||||||
return `**[${filled.join("")}${empty.join("")}] ${secToISO(
|
return `**[${filled.join("")}${empty.join("")}] ${secToISO(duration)}/${secToISO(length)}**`;
|
||||||
duration
|
|
||||||
)}/${secToISO(length)}**`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function secToISO(amount: number): string {
|
export function secToISO(amount: number): string {
|
||||||
@@ -36,27 +34,17 @@ export function volumeMoji(amount: number): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function loopMoji(loop: loopOption): string {
|
export function loopMoji(loop: loopOption): string {
|
||||||
return loop === "AUTO"
|
return loop === "AUTO" ? "🔀" : loop === "LOOP" ? "🔁" : loop === "NONE" ? "⤵️" : "🔂";
|
||||||
? "🔀"
|
|
||||||
: loop === "LOOP"
|
|
||||||
? "🔁"
|
|
||||||
: loop === "NONE"
|
|
||||||
? "⤵️"
|
|
||||||
: "🔂";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function largestCommonSequence(s1: string, s2: string) {
|
export function largestCommonSequence(s1: string, s2: string) {
|
||||||
s1 = s1.toLowerCase().slice(0, 100);
|
s1 = s1.toLowerCase().slice(0, 100);
|
||||||
s2 = s2.toLowerCase().slice(0, 100);
|
s2 = s2.toLowerCase().slice(0, 100);
|
||||||
|
|
||||||
const buffer = Array.from(
|
const buffer = Array.from(Array(s1.length + 1), () => new Array<number>(s2.length + 1).fill(0));
|
||||||
Array(s1.length + 1),
|
|
||||||
() => new Array<number>(s2.length + 1).fill(0)
|
|
||||||
);
|
|
||||||
for (let i = 1; i <= s1.length; i++) {
|
for (let i = 1; i <= s1.length; i++) {
|
||||||
for (let j = 1; j <= s2.length; j++) {
|
for (let j = 1; j <= s2.length; j++) {
|
||||||
if (s1[i - 1] === s2[j - 1])
|
if (s1[i - 1] === s2[j - 1]) buffer[i][j] = buffer[i - 1][j - 1] + 1;
|
||||||
buffer[i][j] = buffer[i - 1][j - 1] + 1;
|
|
||||||
else buffer[i][j] = Math.max(buffer[i - 1][j], buffer[i][j - 1]);
|
else buffer[i][j] = Math.max(buffer[i - 1][j], buffer[i][j - 1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import { Guild, TextChannel } from "discord.js";
|
import { Guild, TextChannel } from "discord.js";
|
||||||
import Player from "./Player.js";
|
|
||||||
|
import Player from "./player.js";
|
||||||
|
|
||||||
export default class Music {
|
export default class Music {
|
||||||
private players = new Map<string, Player>();
|
private players = new Map<string, Player>();
|
||||||
@@ -1,33 +1,25 @@
|
|||||||
import {
|
import {
|
||||||
VoiceConnection,
|
|
||||||
AudioPlayer,
|
AudioPlayer,
|
||||||
createAudioResource,
|
|
||||||
AudioPlayerStatus,
|
AudioPlayerStatus,
|
||||||
joinVoiceChannel,
|
|
||||||
createAudioPlayer,
|
|
||||||
AudioResource,
|
AudioResource,
|
||||||
|
createAudioPlayer,
|
||||||
|
createAudioResource,
|
||||||
DiscordGatewayAdapterCreator,
|
DiscordGatewayAdapterCreator,
|
||||||
VoiceConnectionStatus,
|
|
||||||
entersState,
|
entersState,
|
||||||
|
joinVoiceChannel,
|
||||||
|
VoiceConnection,
|
||||||
|
VoiceConnectionStatus
|
||||||
} from "@discordjs/voice";
|
} from "@discordjs/voice";
|
||||||
|
import { Guild, Message, TextChannel, User, VoiceBasedChannel } from "discord.js";
|
||||||
import {
|
|
||||||
Guild,
|
|
||||||
Message,
|
|
||||||
TextChannel,
|
|
||||||
User,
|
|
||||||
VoiceBasedChannel,
|
|
||||||
} from "discord.js";
|
|
||||||
|
|
||||||
import Music from "./Music.js";
|
|
||||||
import Filter from "./Filter.js";
|
|
||||||
import Queue from "./Queue.js";
|
|
||||||
import { fetchStream } from "./Fetch.js";
|
|
||||||
import I18n from "./I18n.js";
|
|
||||||
|
|
||||||
import ytdl from "discord-ytdl-core";
|
import ytdl from "discord-ytdl-core";
|
||||||
import { track } from "./Types.js";
|
|
||||||
import { largestCommonSequence } from "./Misc.js";
|
import { fetchStream } from "./fetch.js";
|
||||||
|
import Filter from "./filter.js";
|
||||||
|
import I18n from "./i18n.js";
|
||||||
|
import { largestCommonSequence } from "./misc.js";
|
||||||
|
import Music from "./music.js";
|
||||||
|
import Queue from "./queue.js";
|
||||||
|
import { track } from "./types.js";
|
||||||
|
|
||||||
export default class Player {
|
export default class Player {
|
||||||
private music: Music;
|
private music: Music;
|
||||||
@@ -78,23 +70,18 @@ export default class Player {
|
|||||||
public set Volume(x: number) {
|
public set Volume(x: number) {
|
||||||
this.volume = Math.max(0, Math.min(150, x));
|
this.volume = Math.max(0, Math.min(150, x));
|
||||||
|
|
||||||
if (this.resource && this.resource.volume) this.resource.volume.setVolumeLogarithmic(this.volume / 100);
|
if (this.resource && this.resource.volume)
|
||||||
|
this.resource.volume.setVolumeLogarithmic(this.volume / 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
public constructor(
|
public constructor(guild: Guild, music: Music, textChannel: TextChannel) {
|
||||||
guild: Guild,
|
|
||||||
music: Music,
|
|
||||||
textChannel: TextChannel
|
|
||||||
) {
|
|
||||||
this.music = music;
|
this.music = music;
|
||||||
this.guild = guild;
|
this.guild = guild;
|
||||||
this.channel = textChannel;
|
this.channel = textChannel;
|
||||||
|
|
||||||
this.player = createAudioPlayer();
|
this.player = createAudioPlayer();
|
||||||
|
|
||||||
this.player.on(AudioPlayerStatus.Idle, async () =>
|
this.player.on(AudioPlayerStatus.Idle, async () => this.resourceEndResolvable());
|
||||||
this.resourceEndResolvable()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private resourceGenerator(track: track, seek?: number) {
|
private resourceGenerator(track: track, seek?: number) {
|
||||||
@@ -104,14 +91,12 @@ export default class Player {
|
|||||||
filter: "audioonly",
|
filter: "audioonly",
|
||||||
highWaterMark: 1 << 25,
|
highWaterMark: 1 << 25,
|
||||||
seek: seek ? seek / 1000 : undefined,
|
seek: seek ? seek / 1000 : undefined,
|
||||||
encoderArgs: !this.filter.empty()
|
encoderArgs: !this.filter.empty() ? ["-af", this.filter.toString()] : undefined
|
||||||
? ["-af", this.filter.toString()]
|
|
||||||
: undefined,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.resource = createAudioResource(stream, {
|
this.resource = createAudioResource(stream, {
|
||||||
inlineVolume: true,
|
inlineVolume: true,
|
||||||
metadata: track,
|
metadata: track
|
||||||
});
|
});
|
||||||
|
|
||||||
if (seek) this.resource.playbackDuration = seek;
|
if (seek) this.resource.playbackDuration = seek;
|
||||||
@@ -125,8 +110,7 @@ export default class Player {
|
|||||||
|
|
||||||
if (this.queue.next()) {
|
if (this.queue.next()) {
|
||||||
this.play();
|
this.play();
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
this.resource = undefined;
|
this.resource = undefined;
|
||||||
this.player.stop();
|
this.player.stop();
|
||||||
}
|
}
|
||||||
@@ -136,21 +120,18 @@ export default class Player {
|
|||||||
if (this.message) await this.message.delete();
|
if (this.message) await this.message.delete();
|
||||||
|
|
||||||
this.message = await this.channel.send({
|
this.message = await this.channel.send({
|
||||||
embeds: [I18n.en.nowPlaying(track)],
|
embeds: [I18n.en.nowPlaying(track)]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private async search(
|
private async search(query: string, requester: User): Promise<track[] | undefined> {
|
||||||
query: string,
|
|
||||||
requester: User
|
|
||||||
): Promise<track[] | undefined> {
|
|
||||||
const response = await fetchStream(query, {
|
const response = await fetchStream(query, {
|
||||||
dumpSingleJson: true,
|
dumpSingleJson: true,
|
||||||
noWarnings: true,
|
noWarnings: true,
|
||||||
noCheckCertificate: true,
|
noCheckCertificate: true,
|
||||||
flatPlaylist: true,
|
flatPlaylist: true,
|
||||||
skipDownload: true,
|
skipDownload: true,
|
||||||
defaultSearch: "ytsearch",
|
defaultSearch: "ytsearch"
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!response) return undefined;
|
if (!response) return undefined;
|
||||||
@@ -164,17 +145,16 @@ export default class Player {
|
|||||||
title: entry.title,
|
title: entry.title,
|
||||||
thumbnail: `https://img.youtube.com/vi/${entry.id}/default.jpg`,
|
thumbnail: `https://img.youtube.com/vi/${entry.id}/default.jpg`,
|
||||||
duration: entry.duration,
|
duration: entry.duration,
|
||||||
requester: requester,
|
requester: requester
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
tracks.push({
|
tracks.push({
|
||||||
url: `https://youtube.com/watch?v=${response.id}`,
|
url: `https://youtube.com/watch?v=${response.id}`,
|
||||||
title: response.title,
|
title: response.title,
|
||||||
thumbnail: `https://img.youtube.com/vi/${response.id}/default.jpg`,
|
thumbnail: `https://img.youtube.com/vi/${response.id}/default.jpg`,
|
||||||
duration: response.duration,
|
duration: response.duration,
|
||||||
requester: requester,
|
requester: requester
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -199,39 +179,30 @@ export default class Player {
|
|||||||
this.connection = joinVoiceChannel({
|
this.connection = joinVoiceChannel({
|
||||||
channelId: channel.id,
|
channelId: channel.id,
|
||||||
guildId: channel.guildId,
|
guildId: channel.guildId,
|
||||||
adapterCreator: channel.guild
|
adapterCreator: channel.guild.voiceAdapterCreator as DiscordGatewayAdapterCreator
|
||||||
.voiceAdapterCreator as DiscordGatewayAdapterCreator,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.connection.on(
|
this.connection.on(VoiceConnectionStatus.Disconnected, async () => {
|
||||||
VoiceConnectionStatus.Disconnected,
|
try {
|
||||||
async () => {
|
await Promise.race([
|
||||||
try {
|
entersState(
|
||||||
await Promise.race([
|
this.connection as VoiceConnection,
|
||||||
entersState(
|
VoiceConnectionStatus.Signalling,
|
||||||
this.connection as VoiceConnection,
|
10_000
|
||||||
VoiceConnectionStatus.Signalling,
|
),
|
||||||
10_000
|
entersState(
|
||||||
),
|
this.connection as VoiceConnection,
|
||||||
entersState(
|
VoiceConnectionStatus.Connecting,
|
||||||
this.connection as VoiceConnection,
|
10_000
|
||||||
VoiceConnectionStatus.Connecting,
|
)
|
||||||
10_000
|
]);
|
||||||
),
|
} catch (error) {
|
||||||
]);
|
this.destroy();
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
this.destroy();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public async add(
|
public async add(query: string, requester: User, index?: number): Promise<track | undefined> {
|
||||||
query: string,
|
|
||||||
requester: User,
|
|
||||||
index?: number
|
|
||||||
): Promise<track | undefined> {
|
|
||||||
const tracks = await this.search(query, requester);
|
const tracks = await this.search(query, requester);
|
||||||
|
|
||||||
if (!tracks) return;
|
if (!tracks) return;
|
||||||
@@ -246,7 +217,7 @@ export default class Player {
|
|||||||
let diff = 0;
|
let diff = 0;
|
||||||
|
|
||||||
if (typeof query === "string") {
|
if (typeof query === "string") {
|
||||||
this.queue.Tracks.forEach((track, index) => {
|
this.queue.Tracks.forEach((track, index) => {
|
||||||
const tempDiff = largestCommonSequence(track.title, query);
|
const tempDiff = largestCommonSequence(track.title, query);
|
||||||
if (diff < tempDiff) {
|
if (diff < tempDiff) {
|
||||||
diff = tempDiff;
|
diff = tempDiff;
|
||||||
@@ -270,7 +241,7 @@ export default class Player {
|
|||||||
let diff = 0;
|
let diff = 0;
|
||||||
|
|
||||||
if (typeof query === "string") {
|
if (typeof query === "string") {
|
||||||
this.queue.Tracks.forEach((track, index) => {
|
this.queue.Tracks.forEach((track, index) => {
|
||||||
const tempDiff = largestCommonSequence(track.title, query);
|
const tempDiff = largestCommonSequence(track.title, query);
|
||||||
if (diff < tempDiff) {
|
if (diff < tempDiff) {
|
||||||
diff = tempDiff;
|
diff = tempDiff;
|
||||||
@@ -309,8 +280,7 @@ export default class Player {
|
|||||||
if (this.player.state.status === AudioPlayerStatus.Paused) {
|
if (this.player.state.status === AudioPlayerStatus.Paused) {
|
||||||
this.player.unpause();
|
this.player.unpause();
|
||||||
return false;
|
return false;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
this.player.pause();
|
this.player.pause();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { loopOption, track } from "./Types.js";
|
import { loopOption, track } from "./types.js";
|
||||||
|
|
||||||
export default class Queue {
|
export default class Queue {
|
||||||
private tracks: track[] = [];
|
private tracks: track[] = [];
|
||||||
@@ -34,12 +34,10 @@ export default class Queue {
|
|||||||
if (this.position + 1 < this.tracks.length) {
|
if (this.position + 1 < this.tracks.length) {
|
||||||
this.position++;
|
this.position++;
|
||||||
return this.current();
|
return this.current();
|
||||||
}
|
} else if (this.loop === "LOOP") {
|
||||||
else if (this.loop === "LOOP") {
|
|
||||||
this.position = 0;
|
this.position = 0;
|
||||||
return this.current();
|
return this.current();
|
||||||
}
|
} else if (this.loop === "NONE") {
|
||||||
else if (this.loop === "NONE") {
|
|
||||||
this.position = 0;
|
this.position = 0;
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
@@ -54,7 +52,7 @@ export default class Queue {
|
|||||||
|
|
||||||
[this.tracks[currentIndex], this.tracks[randomIndex]] = [
|
[this.tracks[currentIndex], this.tracks[randomIndex]] = [
|
||||||
this.tracks[randomIndex],
|
this.tracks[randomIndex],
|
||||||
this.tracks[currentIndex],
|
this.tracks[currentIndex]
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,8 +62,7 @@ export default class Queue {
|
|||||||
public push(tracks: track[], index?: number): track {
|
public push(tracks: track[], index?: number): track {
|
||||||
if (!index || index >= this.tracks.length) {
|
if (!index || index >= this.tracks.length) {
|
||||||
this.tracks = this.tracks.concat(tracks);
|
this.tracks = this.tracks.concat(tracks);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
this.tracks.splice(Math.max(0, index), 0, ...tracks);
|
this.tracks.splice(Math.max(0, index), 0, ...tracks);
|
||||||
if (this.position >= index) this.position += tracks.length;
|
if (this.position >= index) this.position += tracks.length;
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import { ApplicationCommandData, User, CommandInteraction } from "discord.js";
|
import { ApplicationCommandData, CommandInteraction, User } from "discord.js";
|
||||||
import Client from "./Client.js";
|
|
||||||
|
import Client from "./client.js";
|
||||||
|
|
||||||
export type track = {
|
export type track = {
|
||||||
url: string;
|
url: string;
|
||||||
Reference in new issue
Block a user