Author SHA1 Message Date
deytenit 63e4d85cbb Update dependencies 2024-11-08 22:29:50 +03:00
deytenit d79713eae9 Add privacy policy 2024-11-08 21:27:12 +03:00
deytenit cfb6930ccc Multiplatform docker images from actions 2024-11-08 21:26:06 +03:00
deytenit 6250ba601f Remove prisma support 2024-03-02 14:49:57 +03:00
deytenit 0bc97f89fd Sync pnpm-lock 2024-03-02 14:47:42 +03:00
deytenit ec34590cf7 Documentation complete 2024-03-02 14:42:53 +03:00
31 changed files with 2931 additions and 2095 deletions

No files matched your search

-21
View File
@@ -1,21 +0,0 @@
{
"root": true,
"parser": "@typescript-eslint/parser",
"parserOptions": {
"warnOnUnsupportedTypeScriptVersion": false,
"sourceType": "module"
},
"env": {
"browser": false,
"node": true,
"es6": true
},
"extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended", "prettier"],
"plugins": ["@typescript-eslint", "import", "simple-import-sort"],
"ignorePatterns": ["**/node_modules/**", "/dist/**", "/tests/**"],
"rules": {
"curly": ["error", "all"],
"simple-import-sort/imports": "error",
"simple-import-sort/exports": "error"
}
}
+10 -8
View File
@@ -13,8 +13,8 @@ jobs:
strategy: strategy:
matrix: matrix:
node-version: [20.x] node-version: [22.x]
pnpm-version: [8] pnpm-version: [9]
steps: steps:
- name: Check out the repo - name: Check out the repo
@@ -35,11 +35,6 @@ jobs:
- name: ESLint & Prettier - name: ESLint & Prettier
run: pnpm run lint run: pnpm run lint
- name: Prisma Migration
env:
DATABASE_URL: ${{ secrets.DATABASE_URL }}
run: pnpm exec prisma migrate deploy
- name: Build - name: Build
run: pnpm run build run: pnpm run build
@@ -54,6 +49,12 @@ jobs:
- name: Check out the repo - name: Check out the repo
uses: actions/checkout@v3 uses: actions/checkout@v3
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Docker Hub - name: Log in to Docker Hub
uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1 uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1
with: with:
@@ -65,7 +66,7 @@ jobs:
uses: docker/metadata-action@v5 uses: docker/metadata-action@v5
with: with:
images: | images: |
unknowableshade/quetza deytenit/quetza
# generate Docker tags based on the following events/attributes # generate Docker tags based on the following events/attributes
# on tag event: tag using git tag, and as latest if the tag doesn't contain hyphens (pre-releases) # on tag event: tag using git tag, and as latest if the tag doesn't contain hyphens (pre-releases)
# on push event: tag using git sha, branch name and as latest-dev # on push event: tag using git sha, branch name and as latest-dev
@@ -82,5 +83,6 @@ jobs:
with: with:
context: . context: .
push: true push: true
platforms: linux/amd64,linux/arm64
tags: ${{ steps.meta.outputs.tags }} tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }} labels: ${{ steps.meta.outputs.labels }}
+36
View File
@@ -0,0 +1,36 @@
# Privacy Policy of Quetza
This privacy policy applies to the Discord bot Quetza (hereby referred to as "Quetza")
that was created by Vladimir Eremin (hereby referred to as "Service Provider")
as an Open Source service.
Quetza is intended for use "AS IS",
in compliance with [Discord Privacy Policy](https://discord.com/privacy).
## What information does Quetza store and how is it used?
Quetza does not store any information.
## Do third parties see and/or have access to information obtained by the Quetza?
Since Quetza does not store any information, no data is shared with third parties.
## Changes
This Privacy Policy may be updated from time to time for any reason.
The Service Provider will notify you of any changes to their Privacy Policy
by updating this page with the new Privacy Policy.
You are advised to consult this Privacy Policy regularly for any changes,
as continued use is deemed approval of all changes.
_This privacy policy is effective as of 2024-11-08_
## Your Consent
By using Quetza, you are consenting to the processing of your information
as set forth in this Privacy Policy now and as amended by the Service Provider.
## Contact Us
If you have any questions regarding privacy while using Quetza, or have questions
about the practices, please contact the Service Provider via email at [personal@ermnvldmr.com](mailto:personal@ermnvldmr.com).
+44
View File
@@ -0,0 +1,44 @@
import typescriptEslint from "@typescript-eslint/eslint-plugin";
import globals from "globals";
import tsParser from "@typescript-eslint/parser";
import path from "node:path";
import { fileURLToPath } from "node:url";
import js from "@eslint/js";
import { FlatCompat } from "@eslint/eslintrc";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const compat = new FlatCompat({
baseDirectory: __dirname,
recommendedConfig: js.configs.recommended,
allConfig: js.configs.all
});
export default [
{ ignores: ["**/node_modules/**/*", "dist/**/*", "tests/**/*"] },
...compat.extends("eslint:recommended", "plugin:@typescript-eslint/recommended", "prettier"),
{
plugins: {
"@typescript-eslint": typescriptEslint
},
languageOptions: {
globals: {
...Object.fromEntries(Object.entries(globals.browser).map(([key]) => [key, "off"])),
...globals.node
},
parser: tsParser,
ecmaVersion: "latest",
sourceType: "module",
parserOptions: {
warnOnUnsupportedTypeScriptVersion: false
}
},
rules: {
curly: ["error", "all"]
}
}
];
-2
View File
@@ -4,8 +4,6 @@
* Replies module listing as well as description of each. * Replies module listing as well as description of each.
* *
* Just for the information I guess... * Just for the information I guess...
*
* @packageDocumentation
*/ */
import { ChatInputCommandInteraction, SlashCommandBuilder } from "discord.js"; import { ChatInputCommandInteraction, SlashCommandBuilder } from "discord.js";
-2
View File
@@ -4,8 +4,6 @@
* Replies websocket ping (ping between bot and discord) and real ping (ping to fetch + process). * Replies websocket ping (ping between bot and discord) and real ping (ping to fetch + process).
* *
* @remarks Probably should double their value as two ways, but nvm. * @remarks Probably should double their value as two ways, but nvm.
*
* @packageDocumentation
*/ */
import { ChatInputCommandInteraction, SlashCommandBuilder } from "discord.js"; import { ChatInputCommandInteraction, SlashCommandBuilder } from "discord.js";
+1 -2
View File
@@ -4,9 +4,8 @@
* Resolves creation of an interaction by users. * Resolves creation of an interaction by users.
* *
* @remark Only {@link ChatInputCommand} currently being resolved. * @remark Only {@link ChatInputCommand} currently being resolved.
*
* @packageDocumentation
*/ */
import { Events, Interaction } from "discord.js"; import { Events, Interaction } from "discord.js";
import Client from "$lib/client.js"; import Client from "$lib/client.js";
-2
View File
@@ -5,8 +5,6 @@
* *
* @remarks Will push slash commands, set activity status, * @remarks Will push slash commands, set activity status,
* and log bot's initials. * and log bot's initials.
*
* @packageDocumentation
*/ */
import { generateDependencyReport } from "@discordjs/voice"; import { generateDependencyReport } from "@discordjs/voice";
+1 -1
View File
@@ -11,7 +11,7 @@
* *
* There a lot of speaking because it's as important as $lib. * There a lot of speaking because it's as important as $lib.
* *
* @packageDocumentation * @packageDocumentation
*/ */
const name = "core"; const name = "core";
+15 -2
View File
@@ -1,12 +1,25 @@
/**
* /clear
*
* Clears Player queue entirely.
*
* Possible replies:
* - Success with amount of tracks deleted.
* - Player does not exists.
*/
import { ChatInputCommandInteraction, SlashCommandBuilder } from "discord.js"; import { ChatInputCommandInteraction, SlashCommandBuilder } from "discord.js";
import Client from "$lib/client.js"; import Client from "$lib/client.js";
import logger from "$lib/logger.js"; import logger from "$lib/logger.js";
import Music from "$mlib/music.js";
import replies from "../lib/replies.js"; import replies from "../lib/replies.js";
import { controller } from "../module.js";
async function execute(client: Client, interaction: ChatInputCommandInteraction): Promise<void> { async function execute(
_: Client,
interaction: ChatInputCommandInteraction,
controller: Music
): Promise<void> {
if (!interaction.isChatInputCommand() || !interaction.inCachedGuild() || !interaction.channel) { if (!interaction.isChatInputCommand() || !interaction.inCachedGuild() || !interaction.channel) {
logger.warn("Interaction rejected.", { interaction }); logger.warn("Interaction rejected.", { interaction });
+19 -2
View File
@@ -1,12 +1,29 @@
/**
* /connect
*
* Connects bot to the voice channel.
*
* Just like play but without query.
*
* Possible replies:
* - Success with Voice Channel bot connected to.
* - Requester does not connected to the Voice Channel.
*
* @deprecated Does not make sense.
*/
import { ChatInputCommandInteraction, SlashCommandBuilder } from "discord.js"; import { ChatInputCommandInteraction, SlashCommandBuilder } from "discord.js";
import Client from "$lib/client.js"; import Client from "$lib/client.js";
import logger from "$lib/logger.js"; import logger from "$lib/logger.js";
import Music from "$mlib/music.js";
import replies from "../lib/replies.js"; import replies from "../lib/replies.js";
import { controller } from "../module.js";
async function execute(client: Client, interaction: ChatInputCommandInteraction): Promise<void> { async function execute(
_: Client,
interaction: ChatInputCommandInteraction,
controller: Music
): Promise<void> {
if (!interaction.isChatInputCommand() || !interaction.inCachedGuild() || !interaction.channel) { if (!interaction.isChatInputCommand() || !interaction.inCachedGuild() || !interaction.channel) {
logger.warn("Interaction rejected.", { interaction }); logger.warn("Interaction rejected.", { interaction });
+20 -3
View File
@@ -1,13 +1,30 @@
/**
* /filter <filter id>
*
* Toggles filter that will be applied to the playback.
* Such as nightcore, etc.
*
* If no filter id was provided clears them all.
*
* Possible replies:
* - Success with chosen filter status or filters being cleared.
* - Player does not exists.
*/
import { ChatInputCommandInteraction, SlashCommandBuilder } from "discord.js"; import { ChatInputCommandInteraction, SlashCommandBuilder } from "discord.js";
import Client from "$lib/client.js"; import Client from "$lib/client.js";
import logger from "$lib/logger.js"; import logger from "$lib/logger.js";
import Music from "$mlib/music.js";
import Filter from "../lib/filter.js"; import Filter from "../lib/filter.js";
import replies from "../lib/replies.js"; import replies from "../lib/replies.js";
import { controller } from "../module.js";
async function execute(client: Client, interaction: ChatInputCommandInteraction) { async function execute(
_: Client,
interaction: ChatInputCommandInteraction,
controller: Music
): Promise<void> {
if (!interaction.isChatInputCommand() || !interaction.inCachedGuild() || !interaction.channel) { if (!interaction.isChatInputCommand() || !interaction.inCachedGuild() || !interaction.channel) {
logger.warn("Interaction rejected.", { interaction }); logger.warn("Interaction rejected.", { interaction });
@@ -36,7 +53,7 @@ const data = new SlashCommandBuilder()
option option
.setName("filter") .setName("filter")
.setDescription("Filter to apply.") .setDescription("Filter to apply.")
.setChoices(...Object.values(Filter.FILTERS)) .setChoices(...Filter.filterChoices())
) )
.setDMPermission(false); .setDMPermission(false);
+22 -2
View File
@@ -1,12 +1,32 @@
/**
* /info
*
* Replies with very stylish player info card.
*
* Playback status bar with title, thumbnail and duration.
* Queue length and duration.
* Applied filters.
* Current loop option.
* Player lifetime.
*
* Possible replies:
* - Success with info card.
* - Player does not exists.
*/
import { ChatInputCommandInteraction, SlashCommandBuilder } from "discord.js"; import { ChatInputCommandInteraction, SlashCommandBuilder } from "discord.js";
import Client from "$lib/client.js"; import Client from "$lib/client.js";
import logger from "$lib/logger.js"; import logger from "$lib/logger.js";
import Music from "$mlib/music.js";
import replies from "../lib/replies.js"; import replies from "../lib/replies.js";
import { controller } from "../module.js";
async function execute(client: Client, interaction: ChatInputCommandInteraction) { async function execute(
_: Client,
interaction: ChatInputCommandInteraction,
controller: Music
): Promise<void> {
if (!interaction.isChatInputCommand() || !interaction.inCachedGuild() || !interaction.channel) { if (!interaction.isChatInputCommand() || !interaction.inCachedGuild() || !interaction.channel) {
logger.warn("Interaction rejected.", { interaction }); logger.warn("Interaction rejected.", { interaction });
+16 -2
View File
@@ -1,12 +1,26 @@
/**
* /insert (query) (position)
*
* Inserts specified track/album to the position specified.
*
* Possible replies:
* - Success with first added track info.
* - Player does not exists.
* - No track was added.
*/
import { ChatInputCommandInteraction, SlashCommandBuilder } from "discord.js"; import { ChatInputCommandInteraction, SlashCommandBuilder } from "discord.js";
import Client from "$lib/client.js"; import Client from "$lib/client.js";
import logger from "$lib/logger.js"; import logger from "$lib/logger.js";
import Music from "$mlib/music.js";
import replies from "../lib/replies.js"; import replies from "../lib/replies.js";
import { controller } from "../module.js";
async function execute(client: Client, interaction: ChatInputCommandInteraction) { async function execute(
_: Client,
interaction: ChatInputCommandInteraction,
controller: Music
): Promise<void> {
if (!interaction.isChatInputCommand() || !interaction.inCachedGuild() || !interaction.channel) { if (!interaction.isChatInputCommand() || !interaction.inCachedGuild() || !interaction.channel) {
logger.warn("Interaction rejected.", { interaction }); logger.warn("Interaction rejected.", { interaction });
+19 -2
View File
@@ -1,12 +1,29 @@
/**
* /jump (query)
*
* Jumps to the specified Track from the queue.
* If number was provided - resolves as position at where queue position should be set.
* If string was provided - jumps to the most similar if terms of {@link ../lib/misc#LargestCommonSequence} Track title.
*
* Possible replies:
* - Success with selected track data.
* - Such track does not exists, though cannot be jumped to.
* - Player does not exists.
*/
import { ChatInputCommandInteraction, SlashCommandBuilder } from "discord.js"; import { ChatInputCommandInteraction, SlashCommandBuilder } from "discord.js";
import Client from "$lib/client.js"; import Client from "$lib/client.js";
import logger from "$lib/logger.js"; import logger from "$lib/logger.js";
import Music from "$mlib/music.js";
import replies from "../lib/replies.js"; import replies from "../lib/replies.js";
import { controller } from "../module.js";
async function execute(client: Client, interaction: ChatInputCommandInteraction) { async function execute(
_: Client,
interaction: ChatInputCommandInteraction,
controller: Music
): Promise<void> {
if (!interaction.isChatInputCommand() || !interaction.inCachedGuild() || !interaction.channel) { if (!interaction.isChatInputCommand() || !interaction.inCachedGuild() || !interaction.channel) {
logger.warn("Interaction rejected.", { interaction }); logger.warn("Interaction rejected.", { interaction });
+18 -2
View File
@@ -1,13 +1,29 @@
/**
* /loop (option)
*
* Changes loop option.
*
* @remarks
* @see {@link ../lib/types} for LoopOption definition.
*
* Possible replies:
* - Success with new loop option.
* - Player does not exists.
*/
import { ChatInputCommandInteraction, SlashCommandBuilder } from "discord.js"; import { ChatInputCommandInteraction, SlashCommandBuilder } from "discord.js";
import Client from "$lib/client.js"; import Client from "$lib/client.js";
import logger from "$lib/logger.js"; import logger from "$lib/logger.js";
import Music from "$mlib/music.js";
import replies from "../lib/replies.js"; import replies from "../lib/replies.js";
import { LoopOption } from "../lib/types.js"; import { LoopOption } from "../lib/types.js";
import { controller } from "../module.js";
async function execute(client: Client, interaction: ChatInputCommandInteraction) { async function execute(
_: Client,
interaction: ChatInputCommandInteraction,
controller: Music
): Promise<void> {
if (!interaction.isChatInputCommand() || !interaction.inCachedGuild() || !interaction.channel) { if (!interaction.isChatInputCommand() || !interaction.inCachedGuild() || !interaction.channel) {
logger.warn("Interaction rejected.", { interaction }); logger.warn("Interaction rejected.", { interaction });
+15 -2
View File
@@ -1,12 +1,25 @@
/**
* /next
*
* Skips current track.
*
* Possible replies:
* - Success with confirmation of skip. (even there is nothing to skip)
* - Player does not exists.
*/
import { ChatInputCommandInteraction, SlashCommandBuilder } from "discord.js"; import { ChatInputCommandInteraction, SlashCommandBuilder } from "discord.js";
import Client from "$lib/client.js"; import Client from "$lib/client.js";
import logger from "$lib/logger.js"; import logger from "$lib/logger.js";
import Music from "$mlib/music.js";
import replies from "../lib/replies.js"; import replies from "../lib/replies.js";
import { controller } from "../module.js";
async function execute(client: Client, interaction: ChatInputCommandInteraction) { async function execute(
_: Client,
interaction: ChatInputCommandInteraction,
controller: Music
): Promise<void> {
if (!interaction.isChatInputCommand() || !interaction.inCachedGuild() || !interaction.channel) { if (!interaction.isChatInputCommand() || !interaction.inCachedGuild() || !interaction.channel) {
logger.warn("Interaction rejected.", { interaction }); logger.warn("Interaction rejected.", { interaction });
+15 -2
View File
@@ -1,12 +1,25 @@
/**
* /pause
*
* Toggles playback pause.
*
* Possible replies:
* - Success with setted state (paused, resumed).
* - Player does not exists.
*/
import { ChatInputCommandInteraction, SlashCommandBuilder } from "discord.js"; import { ChatInputCommandInteraction, SlashCommandBuilder } from "discord.js";
import Client from "$lib/client.js"; import Client from "$lib/client.js";
import logger from "$lib/logger.js"; import logger from "$lib/logger.js";
import Music from "$mlib/music.js";
import replies from "../lib/replies.js"; import replies from "../lib/replies.js";
import { controller } from "../module.js";
async function execute(client: Client, interaction: ChatInputCommandInteraction) { async function execute(
_: Client,
interaction: ChatInputCommandInteraction,
controller: Music
): Promise<void> {
if (!interaction.isChatInputCommand() || !interaction.inCachedGuild() || !interaction.channel) { if (!interaction.isChatInputCommand() || !interaction.inCachedGuild() || !interaction.channel) {
logger.warn("Interaction rejected.", { interaction }); logger.warn("Interaction rejected.", { interaction });
+17 -2
View File
@@ -1,12 +1,27 @@
/**
* /play <query>
*
* Starts up the Player.
* If query provided searches corresponding track/album and adds it to the queue end.
*
* Possible replies:
* - Success with first added track info.
* - Denies if requester is not connected to the Voice Channel.
* - No track was added, but player was set.
*/
import { ChatInputCommandInteraction, SlashCommandBuilder } from "discord.js"; import { ChatInputCommandInteraction, SlashCommandBuilder } from "discord.js";
import Client from "$lib/client.js"; import Client from "$lib/client.js";
import logger from "$lib/logger.js"; import logger from "$lib/logger.js";
import Music from "$mlib/music.js";
import replies from "../lib/replies.js"; import replies from "../lib/replies.js";
import { controller } from "../module.js";
async function execute(client: Client, interaction: ChatInputCommandInteraction) { async function execute(
_: Client,
interaction: ChatInputCommandInteraction,
controller: Music
): Promise<void> {
if (!interaction.isChatInputCommand() || !interaction.inCachedGuild() || !interaction.channel) { if (!interaction.isChatInputCommand() || !interaction.inCachedGuild() || !interaction.channel) {
logger.warn("Interaction rejected.", { interaction }); logger.warn("Interaction rejected.", { interaction });
+23 -2
View File
@@ -1,3 +1,20 @@
/**
* /queue
*
* Replies interactive queue with current playing track at the top and 10 tracks from queue on each page.
* Interactiveness provided by buttons:
* - First page.
* - Previous page.
* - Next page.
* - Last page.
*
* Buttons live up to 30 seconds.
*
* Possible replies:
* - Success with interactive queue.
* - Player does not exists.
*/
import { import {
ActionRowBuilder, ActionRowBuilder,
ButtonBuilder, ButtonBuilder,
@@ -10,11 +27,15 @@ import {
import Client from "$lib/client.js"; import Client from "$lib/client.js";
import logger from "$lib/logger.js"; import logger from "$lib/logger.js";
import Music from "$mlib/music.js";
import replies from "../lib/replies.js"; import replies from "../lib/replies.js";
import { controller } from "../module.js";
async function execute(client: Client, interaction: ChatInputCommandInteraction) { async function execute(
_: Client,
interaction: ChatInputCommandInteraction,
controller: Music
): Promise<void> {
if (!interaction.isChatInputCommand() || !interaction.inCachedGuild() || !interaction.channel) { if (!interaction.isChatInputCommand() || !interaction.inCachedGuild() || !interaction.channel) {
logger.warn("Interaction rejected.", { interaction }); logger.warn("Interaction rejected.", { interaction });
+18 -2
View File
@@ -1,12 +1,28 @@
/**
* /remove (query)
*
* Removes Track from the queue.
* If number was provided - resolves as position at where deletion should occurr.
* If string was provided - removes most similar if terms of {@link ../lib/misc#LargestCommonSequence} Track title.
*
* Possible replies:
* - Success with removed track data.
* - Such track does not exists, though cannot be removed.
* - Player does not exists.
*/
import { ChatInputCommandInteraction, SlashCommandBuilder } from "discord.js"; import { ChatInputCommandInteraction, SlashCommandBuilder } from "discord.js";
import Client from "$lib/client.js"; import Client from "$lib/client.js";
import logger from "$lib/logger.js"; import logger from "$lib/logger.js";
import Music from "$mlib/music.js";
import replies from "../lib/replies.js"; import replies from "../lib/replies.js";
import { controller } from "../module.js";
async function execute(client: Client, interaction: ChatInputCommandInteraction) { async function execute(
_: Client,
interaction: ChatInputCommandInteraction,
controller: Music
): Promise<void> {
if (!interaction.isChatInputCommand() || !interaction.inCachedGuild() || !interaction.channel) { if (!interaction.isChatInputCommand() || !interaction.inCachedGuild() || !interaction.channel) {
logger.warn("Interaction rejected.", { interaction }); logger.warn("Interaction rejected.", { interaction });
+16 -2
View File
@@ -1,12 +1,26 @@
/**
* /reshuffle
* Shuffles the queue, so real order is changed.
* DO NOT Confuse it with AUTO LoopOption.
*
* Possible replies:
* - Success with queue being reshuffled.
* - Player does not exists.
*/
import { ChatInputCommandInteraction, SlashCommandBuilder } from "discord.js"; import { ChatInputCommandInteraction, SlashCommandBuilder } from "discord.js";
import Client from "$lib/client.js"; import Client from "$lib/client.js";
import logger from "$lib/logger.js"; import logger from "$lib/logger.js";
import Music from "$mlib/music.js";
import replies from "../lib/replies.js"; import replies from "../lib/replies.js";
import { controller } from "../module.js";
async function execute(client: Client, interaction: ChatInputCommandInteraction) { async function execute(
_: Client,
interaction: ChatInputCommandInteraction,
controller: Music
): Promise<void> {
if (!interaction.isChatInputCommand() || !interaction.inCachedGuild() || !interaction.channel) { if (!interaction.isChatInputCommand() || !interaction.inCachedGuild() || !interaction.channel) {
logger.warn("Interaction rejected.", { interaction }); logger.warn("Interaction rejected.", { interaction });
+21 -2
View File
@@ -1,12 +1,31 @@
/**
* /seek <hrs> <mins> <secs>
*
* Changes current Track playback duration to value given.
*
* @remarks
* If not stated - default value for all imputs is 0.
* Input resolution is defined by FFmpeg.
*
* Possible replies:
* - Success with previous and new playback duration.
* - Player does not exists.
* - No resource is currently playing.
*/
import { ChatInputCommandInteraction, SlashCommandBuilder } from "discord.js"; import { ChatInputCommandInteraction, SlashCommandBuilder } from "discord.js";
import Client from "$lib/client.js"; import Client from "$lib/client.js";
import logger from "$lib/logger.js"; import logger from "$lib/logger.js";
import Music from "$mlib/music.js";
import replies from "../lib/replies.js"; import replies from "../lib/replies.js";
import { controller } from "../module.js";
async function execute(client: Client, interaction: ChatInputCommandInteraction) { async function execute(
_: Client,
interaction: ChatInputCommandInteraction,
controller: Music
): Promise<void> {
if (!interaction.isChatInputCommand() || !interaction.inCachedGuild() || !interaction.channel) { if (!interaction.isChatInputCommand() || !interaction.inCachedGuild() || !interaction.channel) {
logger.warn("Interaction rejected.", { interaction }); logger.warn("Interaction rejected.", { interaction });
+17 -2
View File
@@ -1,12 +1,27 @@
/**
* /stop
*
* Destroys player of the Guild where it was emitted.
* Also disconnects user from Voice Channel Quetza was in.
*
* Possible replies:
* - Success with player being destroyed.
* - Player does not exists.
*/
import { ChatInputCommandInteraction, SlashCommandBuilder } from "discord.js"; import { ChatInputCommandInteraction, SlashCommandBuilder } from "discord.js";
import Client from "$lib/client.js"; import Client from "$lib/client.js";
import logger from "$lib/logger.js"; import logger from "$lib/logger.js";
import Music from "$mlib/music.js";
import replies from "../lib/replies.js"; import replies from "../lib/replies.js";
import { controller } from "../module.js";
async function execute(client: Client, interaction: ChatInputCommandInteraction) { async function execute(
_: Client,
interaction: ChatInputCommandInteraction,
controller: Music
): Promise<void> {
if (!interaction.isChatInputCommand() || !interaction.inCachedGuild() || !interaction.channel) { if (!interaction.isChatInputCommand() || !interaction.inCachedGuild() || !interaction.channel) {
logger.warn("Interaction rejected.", { interaction }); logger.warn("Interaction rejected.", { interaction });
+18 -3
View File
@@ -1,19 +1,34 @@
/**
* /volume (amount)
*
* Sets volume of {@link ../lib/player#Player | Player} in percent scale,
* clamping it in range defined in Player.
*
* Possible replies:
* - Success with new volume value.
* - Player does not exists.
*/
import { ChatInputCommandInteraction, SlashCommandBuilder } from "discord.js"; import { ChatInputCommandInteraction, SlashCommandBuilder } from "discord.js";
import Client from "$lib/client.js"; import Client from "$lib/client.js";
import logger from "$lib/logger.js"; import logger from "$lib/logger.js";
import Music from "$mlib/music.js";
import replies from "../lib/replies.js"; import replies from "../lib/replies.js";
import { controller } from "../module.js";
async function execute(client: Client, interaction: ChatInputCommandInteraction) { async function execute(
_: Client,
interaction: ChatInputCommandInteraction,
controller: Music
): Promise<void> {
if (!interaction.isChatInputCommand() || !interaction.inCachedGuild() || !interaction.channel) { if (!interaction.isChatInputCommand() || !interaction.inCachedGuild() || !interaction.channel) {
logger.warn("Interaction rejected.", { interaction }); logger.warn("Interaction rejected.", { interaction });
return; return;
} }
const volume = interaction.options.getInteger("volume") ?? 100; const volume = interaction.options.getInteger("volume", true);
const player = controller.get(interaction.guild, interaction.channel); const player = controller.get(interaction.guild, interaction.channel);
@@ -3,8 +3,6 @@
* *
* Monitors voice states of attended guilds. * Monitors voice states of attended guilds.
* If Quetza happens to be alone in the Voice Channel - destroys guilds player and disconnects. * If Quetza happens to be alone in the Voice Channel - destroys guilds player and disconnects.
*
* @packageDocumentation
*/ */
import { BaseGuildVoiceChannel, User, VoiceState } from "discord.js"; import { BaseGuildVoiceChannel, User, VoiceState } from "discord.js";
-2
View File
@@ -1,7 +1,5 @@
/** /**
* @see ../../../src/lib/error.ts * @see ../../../src/lib/error.ts
*
* @packageDocumentation
*/ */
import QuetzaError from "$lib/error.js"; import QuetzaError from "$lib/error.js";
+14 -2
View File
@@ -52,6 +52,18 @@ export default class Filter {
*/ */
private switches_ = new Map<filterPreset, filterValue>(); private switches_ = new Map<filterPreset, filterValue>();
/**
* Returns filters as Discord API Choices compatible array.
*
* @returns {@link Filter#FILTERS} as { name: FILTERS[key].name, value: key }.
*/
public static filterChoices(): { name: string; value: string }[] {
return Object.entries(Filter.FILTERS).map(([key, value]) => ({
name: value.name,
value: key
}));
}
/** /**
* Converts active {@link filterValue | filterValues} to array. * Converts active {@link filterValue | filterValues} to array.
* *
@@ -101,9 +113,9 @@ export default class Filter {
} }
/** /**
* Converts active filters to FFmpeg compatable argument. * Converts active filters to FFmpeg compatible argument.
* *
* @returns FFmpeg compatable argument representing active filters. * @returns FFmpeg compatible argument representing active filters.
*/ */
public toString(): string { public toString(): string {
return this.toggled() return this.toggled()
+21 -18
View File
@@ -1,6 +1,6 @@
{ {
"name": "quetza", "name": "quetza",
"version": "2024.3.0", "version": "2024.11.0",
"description": "Awesome Discord bot that performs various duties", "description": "Awesome Discord bot that performs various duties",
"type": "module", "type": "module",
"main": "./dist/src/index.js", "main": "./dist/src/index.js",
@@ -15,7 +15,7 @@
"license": "MIT", "license": "MIT",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git+https://github.com/unknowableshade/Quetza.git" "url": "git+https://github.com/deytenit/Quetza.git"
}, },
"author": { "author": {
"name": "Vladimir Eremin", "name": "Vladimir Eremin",
@@ -23,32 +23,35 @@
"url": "https://ermnvldmr.com" "url": "https://ermnvldmr.com"
}, },
"bugs": { "bugs": {
"url": "https://github.com/unknowableshade/Quetza/issues" "url": "https://github.com/deytenit/Quetza/issues"
}, },
"readme": "https://github.com/unknowableshade/Quetza#readme", "readme": "https://github.com/deytenit/Quetza#readme",
"engines": { "engines": {
"node": "20.x.x", "node": "22.x.x",
"npm": "*" "npm": "*"
}, },
"dependencies": { "dependencies": {
"@discordjs/opus": "^0.9.0", "@discordjs/opus": "^0.9.0",
"@discordjs/voice": "^0.16.1", "@discordjs/voice": "^0.17.0",
"discord.js": "^14.14.1", "discord.js": "^14.16.3",
"prism-media": "^1.3.5", "prism-media": "^1.3.5",
"tweetnacl": "^1.0.3", "tweetnacl": "^1.0.3",
"winston": "^3.11.0" "winston": "^3.16.0"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^20.11.24", "@eslint/eslintrc": "^3.1.0",
"@typescript-eslint/eslint-plugin": "^7.1.0", "@eslint/js": "^9.14.0",
"@typescript-eslint/parser": "^7.1.0", "@types/node": "^22.9.0",
"eslint": "^8.57.0", "@typescript-eslint/eslint-plugin": "^8.13.0",
"@typescript-eslint/parser": "^8.13.0",
"eslint": "^9.14.0",
"eslint-config-prettier": "^9.1.0", "eslint-config-prettier": "^9.1.0",
"eslint-plugin-import": "^2.29.1", "eslint-plugin-import": "^2.31.0",
"eslint-plugin-simple-import-sort": "^12.0.0", "eslint-plugin-simple-import-sort": "^12.1.1",
"mocha": "^10.3.0", "globals": "^15.12.0",
"prettier": "^3.2.5", "mocha": "^10.8.2",
"tsc-alias": "^1.8.8", "prettier": "^3.3.3",
"typescript": "^5.3.3" "tsc-alias": "^1.8.10",
"typescript": "^5.6.3"
} }
} }
+2496 -1999
View File
File diff suppressed because it is too large. Load diff
+19
View File
@@ -0,0 +1,19 @@
#!/bin/bash
set -e
mkdir -p .git/hooks
HOOK_CONTENT="#!/bin/sh
pnpm run lint
if [ \$? -ne 0 ]; then
echo 'Pre-commit hook failed. Please fix the issues and commit again.'
exit 1
fi
"
echo "$HOOK_CONTENT" > .git/hooks/pre-commit
chmod +x .git/hooks/pre-commit
echo "Pre-commit hook installed successfully!"