mirror of
https://github.com/migatu/conjurer.git
synced 2026-07-14 13:34:40 +00:00
a64fb2da57
Make the stable 'working copy' bot the canonical code at the repository
root so the install/deploy scripts operate against it again.
- Move working_copy/* to root (bot entrypoint is bot.py)
- Restore root-level install/ops scripts from c4fa88e (deploy.sh,
install_main_bot.sh, status_report.*, conjurer.service, etc.)
- Fix deploy.sh: copy bot.py (was thin_client.py) and add the
conanjurer_* modules; bump command count
- Remove side-by-side variant dirs (backup_old_docker, prototype_one,
prototype_musician_one, musician_old, working_copy) and docker cruft
- Keep components as subdirs: conjurer_librarian, conjurer_musician,
spotify_dl, yt_dlp, fonts, utils, docs
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
810 lines
38 KiB
Python
810 lines
38 KiB
Python
import asyncio
|
|
import logging
|
|
import random
|
|
import re
|
|
from datetime import datetime
|
|
from sys import platform
|
|
|
|
import discord
|
|
import eyed3
|
|
from discord.ext import commands, tasks
|
|
|
|
import music_functions
|
|
from ai_functions import handle_response
|
|
from communication_subroutine import PREPPED_TRACKS
|
|
from constants import MESSAGE_TABLE_MUZYKA, MUZYKA, SEPARATOR_FILE_PATH
|
|
from other_functions import get_stats
|
|
|
|
|
|
class MusicModule(commands.Cog):
|
|
def __init__(self, bot, logger_name):
|
|
self.bot = bot
|
|
self.logger = logging.getLogger(logger_name)
|
|
|
|
@commands.hybrid_command(
|
|
name="krecimy_pornola",
|
|
description="Wiadomo co, dla kogo i po co",
|
|
)
|
|
@commands.has_any_role('Legenda', 'Jarl', 'Thane' , 'Bartender')
|
|
async def krecimy_pornola(self, ctx):
|
|
"""
|
|
Download a music number from youtube.
|
|
|
|
:param ctx: ctx stands for "context" and is a parameter commonly used in Discord.py commands. It
|
|
represents the context in which the command was invoked, including information such as the message,
|
|
the channel, the server, and the user who invoked the command. It allows the command to interact
|
|
with the Discord API and
|
|
"""
|
|
await ctx.send("Dej mnie chwilkę")
|
|
self.logger.info("Pornol")
|
|
async with ctx.typing():
|
|
# wyciagnij linka z kontekstu
|
|
content = ctx.message.content.split()
|
|
for item_yt in content:
|
|
if re.match("http.*", item_yt):
|
|
sciezka, files = await music_functions.get_file(
|
|
ctx, "Pornol", item_yt
|
|
)
|
|
if files:
|
|
self.logger.info("Pornol udany")
|
|
await ctx.send(
|
|
f"Jest w tajnym archiwum pod adresem{sciezka})"
|
|
)
|
|
|
|
@commands.hybrid_command(
|
|
name="co_na_plejliscie_wariacie",
|
|
description="Wyswietl kawalki ktore sa na pocztku list radia",
|
|
guild=discord.Object(id=664789470779932693),
|
|
)
|
|
@commands.has_any_role('Nocna Zmiana', 'Jarl', 'Thane' , 'Bartender')
|
|
|
|
async def co_na_plejliscie_wariacie(self, ctx):
|
|
"""
|
|
Download a music number from youtube.
|
|
|
|
:param ctx: ctx stands for "context" and is a parameter commonly used in Discord.py commands. It
|
|
represents the context in which the command was invoked, including information such as the message,
|
|
the channel, the server, and the user who invoked the command. It allows the command to interact
|
|
with the Discord API and
|
|
"""
|
|
await ctx.send("Dej mnie chwilkę")
|
|
async with ctx.typing():
|
|
self.logger.info("plejlista")
|
|
self.logger.info(PREPPED_TRACKS)
|
|
await ctx.send(
|
|
f"Didżej Hammer i jego sztuczna inteligencja (||he he||) prezentują: \n- obecnie grany jest {(PREPPED_TRACKS['now_playing']).rstrip()} (wg metadanych: {PREPPED_TRACKS['meta']}) \n- następny będzie{(PREPPED_TRACKS['next']).rstrip()} \n- na liście priorytetowej {(PREPPED_TRACKS['priority']).rstrip()} \n- na liście hitów obecnie czeka kawałek {(PREPPED_TRACKS['hit']).rstrip()} \n- na liście wszystkich kawałków {(PREPPED_TRACKS['all']).rstrip()} \n- najświeższym zamówieniem od słuchaczy jest {(PREPPED_TRACKS['requests']).rstrip()} \nZ kolei jingiel to: {(PREPPED_TRACKS['jingles']).rstrip()}"
|
|
)
|
|
|
|
@tasks.loop(seconds=1)
|
|
async def check_music(self):
|
|
"""
|
|
This Python function continuously checks for music playback in a voice client and plays music if
|
|
conditions are met.
|
|
"""
|
|
if self.bot.voice_clients:
|
|
voice_client = self.bot.voice_clients[0]
|
|
if (
|
|
voice_client
|
|
and voice_client.is_connected()
|
|
and not voice_client.is_playing()
|
|
and not voice_client.is_paused()
|
|
):
|
|
await self.play(MUZYKA["ctx"], MUZYKA["requester"])
|
|
await asyncio.sleep(2)
|
|
|
|
@commands.hybrid_command(
|
|
name="dej_co_z_jutuba",
|
|
description="Podaj link do youtube - sciagnie i doda muzyke",
|
|
guild=discord.Object(id=664789470779932693),
|
|
)
|
|
@commands.has_any_role('Nocna Zmiana', 'Jarl', 'Thane' , 'Bartender')
|
|
async def dej_co_z_jutuba(self, ctx):
|
|
"""
|
|
Download a music number from youtube.
|
|
|
|
:param ctx: ctx stands for "context" and is a parameter commonly used in Discord.py commands. It
|
|
represents the context in which the command was invoked, including information such as the message,
|
|
the channel, the server, and the user who invoked the command. It allows the command to interact
|
|
with the Discord API and
|
|
"""
|
|
await ctx.send("Dej mnie chwilkę")
|
|
self.logger.info("Jutub")
|
|
async with ctx.typing():
|
|
# wyciagnij linka z kontekstu
|
|
content = ctx.message.content.split()
|
|
for item_yt in content:
|
|
if re.match("http.*", item_yt):
|
|
_, files = await music_functions.get_file(ctx, "Youtube", item_yt)
|
|
if files:
|
|
for file_iter in files:
|
|
global MUZYKA # pylint: disable=global-variable-not-assigned
|
|
MUZYKA["queue"].insert(0, file_iter)
|
|
music_functions.MUSIC_FILE_LIST.update_file_list(file_iter)
|
|
MUZYKA["requester"].insert(0, ctx.author)
|
|
await ctx.send(f"Dodałem do listy {file_iter}")
|
|
self.logger.info("Jutub udany")
|
|
|
|
@commands.hybrid_command(
|
|
name="dej_co_ze_spotifaja",
|
|
description="Podaj link do spotify - sciagnie i doda muzyke",
|
|
guild=discord.Object(id=664789470779932693),
|
|
)
|
|
@commands.has_any_role('Nocna Zmiana', 'Jarl', 'Thane' , 'Bartender')
|
|
async def dej_co_ze_spotifaja(self, ctx):
|
|
"""
|
|
Get a playlist or a music number from Spotify.
|
|
|
|
:param ctx: ctx stands for "context" and is a parameter commonly used in Discord.py commands. It
|
|
represents the context in which the command was invoked, including information such as the message,
|
|
the channel, the server, and the user who invoked the command. This parameter is required in all
|
|
Discord.py commands
|
|
"""
|
|
self.logger.info("Spotifaj")
|
|
await ctx.send("Dej mnie chwilkę")
|
|
async with ctx.typing():
|
|
# wyciagnij linka z kontekstu
|
|
content = ctx.message.content.split()
|
|
for item in content:
|
|
if re.match("http.*", item):
|
|
dir_path, files = await music_functions.get_file(
|
|
ctx, "Spotify", item
|
|
)
|
|
if platform == "win32":
|
|
separator = "\\"
|
|
else:
|
|
separator = "/"
|
|
for file in files:
|
|
file_path = (
|
|
dir_path
|
|
+ separator
|
|
+ file["artist"]
|
|
+ " - "
|
|
+ file["name"]
|
|
+ ".mp3"
|
|
)
|
|
global MUZYKA # pylint: disable=global-variable-not-assigned
|
|
MUZYKA["queue"].insert(
|
|
0,
|
|
dir_path
|
|
+ separator
|
|
+ file["artist"]
|
|
+ " - "
|
|
+ file["name"]
|
|
+ ".mp3",
|
|
)
|
|
MUZYKA["requester"].insert(0, ctx.author)
|
|
music_functions.MUSIC_FILE_LIST.update_file_list(file_path)
|
|
await ctx.send(
|
|
f"Dodałem do listy {dir_path}{file['artist']} - + {file['name']}.mp3"
|
|
)
|
|
self.logger.info("Spotifaj udany")
|
|
|
|
# MUSIC BOT PART
|
|
@commands.hybrid_command(
|
|
name="cisza",
|
|
description="Wyłącza muzykę i czyści plejliste.",
|
|
guild=discord.Object(id=664789470779932693),
|
|
)
|
|
@commands.has_any_role('Nocna Zmiana', 'Jarl', 'Thane' , 'Bartender')
|
|
async def cisza(self, ctx):
|
|
"""
|
|
Stop playback of the music and clear the queue.
|
|
|
|
:param ctx: ctx stands for "context" and is a parameter commonly used in Discord.py commands. It
|
|
represents the context in which the command was invoked, including information such as the message,
|
|
the channel, the server, and the user who invoked the command. This parameter is required in all
|
|
Discord.py commands
|
|
"""
|
|
self.logger.info("Stop")
|
|
global MUZYKA # pylint: disable=global-variable-not-assigned
|
|
MUZYKA["ctx"] = None
|
|
voice_client = self.bot.voice_clients[0]
|
|
self.check_music.stop()
|
|
if voice_client.is_connected():
|
|
await self.disconnect(ctx=ctx)
|
|
while MUZYKA["queue"]:
|
|
MUZYKA["queue"].pop()
|
|
MUZYKA["requester"].pop()
|
|
self.logger.info("Stop completed")
|
|
|
|
@commands.hybrid_command(
|
|
name="dalej",
|
|
description="Przerzuca na następny kawałek",
|
|
guild=discord.Object(id=664789470779932693),
|
|
)
|
|
@commands.has_any_role('Nocna Zmiana', 'Jarl', 'Thane' , 'Bartender')
|
|
async def dalej(self, ctx):
|
|
"""
|
|
Play next track in queue.
|
|
|
|
:param ctx: ctx stands for "context" and is a parameter commonly used in Discord.py commands. It
|
|
represents the context in which a command is being executed, including information such as the
|
|
message, the channel, the server, and the user who invoked the command. The context object is used
|
|
to access and manipulate this
|
|
"""
|
|
if ctx:
|
|
self.logger.info("Ctx defined for dalej")
|
|
self.logger.info("Next")
|
|
voice_client = self.bot.voice_clients[0]
|
|
if voice_client.is_connected():
|
|
voice_client.stop()
|
|
self.logger.info("Next completed")
|
|
|
|
@commands.hybrid_command(
|
|
name="daj_mi_chwile",
|
|
description="Pauzuje",
|
|
guild=discord.Object(id=664789470779932693),
|
|
)
|
|
@commands.has_any_role('Nocna Zmiana', 'Jarl', 'Thane' , 'Bartender')
|
|
async def daj_mi_chwile(self, ctx):
|
|
"""
|
|
Pause music playback.
|
|
|
|
:param ctx: ctx stands for "context" and is a parameter commonly used in Discord.py commands. It
|
|
represents the context in which the command was invoked, including information such as the message,
|
|
the channel, the server, and the user who invoked the command. This parameter is required in most
|
|
Discord.py commands and is
|
|
"""
|
|
if ctx:
|
|
self.logger.info("Ctx defined for pause")
|
|
|
|
self.logger.info("Pause")
|
|
voice_client = self.bot.voice_clients[0]
|
|
if voice_client.is_connected():
|
|
voice_client.pause()
|
|
self.logger.info("Pause completed")
|
|
|
|
@commands.hybrid_command(
|
|
name="graj_dalej",
|
|
description="Odpauzowuje",
|
|
guild=discord.Object(id=664789470779932693),
|
|
)
|
|
@commands.has_any_role('Nocna Zmiana', 'Jarl', 'Thane' , 'Bartender')
|
|
async def graj_dalej(self, ctx):
|
|
"""
|
|
Unpause music and continue playback.
|
|
|
|
:param ctx: ctx stands for "context" and is a parameter commonly used in Discord.py commands. It
|
|
represents the context in which the command was invoked, including information such as the message,
|
|
the channel, the server, and the user who invoked the command. This parameter is required in all
|
|
Discord.py commands
|
|
"""
|
|
if ctx:
|
|
self.logger.info("Ctx defined for graj_dalej")
|
|
self.logger.info("Unpause")
|
|
voice_client = self.bot.voice_clients[0]
|
|
if voice_client.is_paused():
|
|
voice_client.resume()
|
|
self.logger.info("Unpause completed")
|
|
|
|
@commands.hybrid_command(
|
|
name="zagraj_mi_kawalek",
|
|
description="Wyszukuje w bibliotece muzycznej Hammera kawałek który ma zostać zagrany",
|
|
guild=discord.Object(id=664789470779932693),
|
|
)
|
|
@commands.has_any_role('Nocna Zmiana', 'Jarl', 'Thane' , 'Bartender')
|
|
async def zagraj_mi_kawalek(self, ctx):
|
|
"""
|
|
Play a song or music piece in response to a command
|
|
triggered by a user in a Discord chat context.
|
|
|
|
:param ctx: ctx stands for "context" and is a parameter commonly used in Discord.py commands. It
|
|
contains information about the context in which the command was invoked, such as the message, the
|
|
channel, the server, and the user who invoked the command. This information can be used to perform
|
|
various actions, such
|
|
"""
|
|
async with ctx.typing():
|
|
search_time_glob = datetime.now()
|
|
self.logger.info("Zaczynam szukać timestamp %s", datetime.now())
|
|
file = await self.wyszukaj(ctx=ctx)
|
|
self.logger.info(
|
|
"Koniec szukania(timestamp %s zajęło %s",
|
|
datetime.now(),
|
|
datetime.now() - search_time_glob,
|
|
)
|
|
|
|
if file:
|
|
for plik in file:
|
|
global MUZYKA # pylint: disable=global-variable-not-assigned
|
|
MUZYKA["queue"].insert(0, plik[1])
|
|
MUZYKA["requester"].insert(0, ctx.author)
|
|
metadata = eyed3.load(plik[1])
|
|
reply = (
|
|
"Dodałem do playlisty {plik[1]} z prywatnej kolekcji Hammera."
|
|
)
|
|
if metadata.tag.title:
|
|
reply = f"Dodałem do playlisty kawalek {metadata.tag.title}"
|
|
if metadata.tag.artist:
|
|
reply += f" wykonawcy {metadata.tag.artist}"
|
|
if metadata.tag.album:
|
|
reply += f" z albumu {metadata.tag.album}"
|
|
reply += (
|
|
" z prywatnej kolekcji Hammera i na Twoją specjalną rpośbę."
|
|
)
|
|
await ctx.send(reply)
|
|
else:
|
|
await ctx.send(
|
|
"Obawiam się że nie mogę nic znaleźć u siebie. Spróbuj komendy '$dej_co_ze_spotifaja' jeśli masz link"
|
|
)
|
|
|
|
@commands.hybrid_command(
|
|
name="zrob_mi_plejliste",
|
|
description="Generuje playliste - param1 - dlugosc, potem slowa wyszukiwania",
|
|
guild=discord.Object(id=664789470779932693),
|
|
)
|
|
@commands.has_any_role('Nocna Zmiana', 'Jarl', 'Thane' , 'Bartender')
|
|
async def zrob_mi_plejliste(self, ctx):
|
|
"""
|
|
Generate a playlist in queue. First word in this command shall be int defining length of the playlist.
|
|
Rest of the line are search terms.
|
|
|
|
:param ctx: ctx stands for "context" and is a parameter commonly used in Discord.py commands. It
|
|
represents the context in which the command was invoked, including information such as the message,
|
|
the channel, the server, and the user who invoked the command. This parameter is required in all
|
|
Discord.py commands
|
|
"""
|
|
reply = "Wygenerowana plejlista:\n"
|
|
async with ctx.typing():
|
|
self.logger.info("Zaczynam szukać timestamp %s", datetime.now())
|
|
search_time_glob = datetime.now()
|
|
|
|
dlugosc_playlisty = ctx.message.content.split()[1]
|
|
file = await music_functions.wyszukaj(ctx=ctx, how_many=dlugosc_playlisty)
|
|
self.logger.info(
|
|
"Koniec szukania(timestamp %s zajęło %s",
|
|
datetime.now(),
|
|
datetime.now() - search_time_glob,
|
|
)
|
|
index = 1
|
|
if file:
|
|
for plik in file:
|
|
if plik[1]:
|
|
self.logger.info(plik)
|
|
global MUZYKA # pylint: disable=global-variable-not-assigned
|
|
MUZYKA["queue"].insert(0, plik[1])
|
|
MUZYKA["requester"].insert(0, ctx.author)
|
|
metadata = eyed3.load(plik[1])
|
|
if metadata and metadata.tag:
|
|
if metadata.tag.title:
|
|
reply += f"{index} {metadata.tag.title}"
|
|
else:
|
|
reply += (
|
|
f"{index}. {plik[1]} z prywatnej kolekcji Hammera."
|
|
)
|
|
|
|
if metadata.tag.artist:
|
|
reply += f" wykonawcy {metadata.tag.artist}"
|
|
if metadata.tag.album:
|
|
reply += f" z albumu {metadata.tag.album}"
|
|
if metadata.tag.title:
|
|
reply += " z prywatnej kolekcji Hammera i na Twoją specjalną rpośbę.\n"
|
|
else:
|
|
reply += (
|
|
f"{index}. {plik[1]} z prywatnej kolekcji Hammera.\n"
|
|
)
|
|
|
|
index += 1
|
|
if len(reply) > 1800:
|
|
await ctx.send(reply)
|
|
reply = ""
|
|
else:
|
|
await ctx.send(
|
|
"Obawiam się że nie mogę nic znaleźć u siebie. Spróbuj komendy '$dej_co_ze_spotifaja' jeśli masz link"
|
|
)
|
|
await ctx.send(reply)
|
|
self.logger.info("Plejlista zrobiona")
|
|
|
|
@commands.hybrid_command(
|
|
name="zagraj_muzyke_mego_ludu",
|
|
description="Gra muzyke wyszukana na bazie tematow konwersacji na kanale NZ",
|
|
guild=discord.Object(id=664789470779932693),
|
|
)
|
|
@commands.has_any_role('Nocna Zmiana', 'Jarl', 'Thane' , 'Bartender')
|
|
async def zagraj_muzyke_mego_ludu(self, ctx):
|
|
"""
|
|
Play completeley random playlist based on messaging history.
|
|
|
|
:param ctx: ctx stands for "context" and is typically used in Discord.py commands to represent the
|
|
context in which the command was invoked. This includes information such as the message, the
|
|
channel, the author, and other relevant details. In this case, it is being passed as a parameter to
|
|
the `get_image
|
|
"""
|
|
stats = {}
|
|
if ctx:
|
|
self.logger.info("Zagraj muzyke mego ludu: wywolane")
|
|
stat_iter = get_stats(self.bot, ctx, MUZYKA_MOJEGO_LUDU_HISTORIA)
|
|
async for name, how_many in stat_iter:
|
|
if len(name) > 3:
|
|
stats[name] = how_many
|
|
|
|
sorted_stats = sorted(stats.items(), key=lambda x: x[1])
|
|
self.logger.info("Zagraj muzyke mego ludu:zebrano statystyki")
|
|
key_words = []
|
|
for stat in sorted_stats:
|
|
key_words.append(stat[0])
|
|
self.logger.info(sorted_stats[:MUZYKA_MOJEGO_LUDU_SLOWA_KLUCZOWE])
|
|
self.logger.info(key_words[:MUZYKA_MOJEGO_LUDU_SLOWA_KLUCZOWE])
|
|
self.logger.info(sorted_stats[-MUZYKA_MOJEGO_LUDU_SLOWA_KLUCZOWE:])
|
|
self.logger.info(key_words[-MUZYKA_MOJEGO_LUDU_SLOWA_KLUCZOWE:])
|
|
|
|
final_key_words = key_words[:MUZYKA_MOJEGO_LUDU_SLOWA_KLUCZOWE]
|
|
final_key_words.extend(key_words[-MUZYKA_MOJEGO_LUDU_SLOWA_KLUCZOWE:])
|
|
reply = "Wygenerowana plejlista:\n"
|
|
async with ctx.typing():
|
|
self.logger.info(
|
|
"Zagraj muzyke mego ludu:Zaczynam szukać timestamp %s", datetime.now()
|
|
)
|
|
search_time_glob = datetime.now()
|
|
file = await music_functions.wyszukaj(
|
|
ctx=ctx,
|
|
how_many=MUZYKA_MOJEGO_LUDU_PLAJLISTA,
|
|
slowa_kluczowe=final_key_words,
|
|
)
|
|
self.logger.info("Zagraj muzyke mego ludu:wygenerowano plejliste")
|
|
self.logger.info(file)
|
|
self.logger.info(
|
|
"Zagraj muzyke mego ludu: Koniec szukania(timestamp %s zajęło %s",
|
|
datetime.now(),
|
|
datetime.now() - search_time_glob,
|
|
)
|
|
index = 1
|
|
if file:
|
|
for plik in file:
|
|
global MUZYKA # pylint: disable=global-variable-not-assigned
|
|
MUZYKA["queue"].insert(0, plik[1])
|
|
MUZYKA["requester"].insert(0, ctx.author)
|
|
metadata = eyed3.load(plik[1])
|
|
if metadata and metadata.tag:
|
|
if metadata.tag.title:
|
|
reply += f"{index} {metadata.tag.title}"
|
|
else:
|
|
reply += f"{index}. {plik[1]} z prywatnej kolekcji Hammera."
|
|
|
|
if metadata.tag.artist:
|
|
reply += f" wykonawcy {metadata.tag.artist}"
|
|
if metadata.tag.album:
|
|
reply += f" z albumu {metadata.tag.album}"
|
|
if metadata.tag.title:
|
|
reply += " z prywatnej kolekcji Hammera i na Twoją specjalną rpośbę.\n"
|
|
else:
|
|
reply += f"{index}. {plik[1]} z prywatnej kolekcji Hammera.\n"
|
|
|
|
index += 1
|
|
if len(reply) > 1800:
|
|
await ctx.send(reply)
|
|
reply = ""
|
|
else:
|
|
await ctx.send(
|
|
"Obawiam się że nie mogę nic znaleźć u siebie. Spróbuj komendy '$dej_co_ze_spotifaja' jeśli masz link"
|
|
)
|
|
await ctx.send(reply)
|
|
self.logger.info("Plejlista zrobiona")
|
|
|
|
@commands.hybrid_command(
|
|
name="parametry_muzyki_mego_ludu",
|
|
description="Konfiguruje komende zagraj muzyke mojego ludu",
|
|
guild=discord.Object(id=664789470779932693),
|
|
)
|
|
@commands.has_any_role('Nocna Zmiana', 'Jarl', 'Thane' , 'Bartender')
|
|
async def parametry_muzyki_mego_ludu(
|
|
self, ctx, ile_historii=1500, ile_slow_kluczowych=15, jak_dluga_plejlista=30
|
|
):
|
|
"""
|
|
The function `parametry_muzyki_mego_ludu` sets global variables for the number of history entries,
|
|
number of keywords, and length of playlist for a music application.
|
|
|
|
:param ctx: The `ctx` parameter is typically used in Discord.py, a Python library for creating
|
|
Discord bots. It represents the context of the command being executed, including information about
|
|
the message, the server, and the user who invoked the command
|
|
:param ile_historii: The parameter "ile_historii" represents the number of history items for the
|
|
music playlist, defaults to 1500 (optional)
|
|
:param ile_slow_kluczowych: The parameter "ile_slow_kluczowych" represents the number of keywords or
|
|
key phrases related to music that you want to include in your analysis or search, defaults to 30
|
|
(optional)
|
|
:param jak_dluga_plejlista: The parameter "jak_dluga_plejlista" determines the length of the
|
|
playlist. It specifies how many songs should be included in the playlist, defaults to 30 (optional)
|
|
"""
|
|
|
|
if ctx:
|
|
async with ctx.typing():
|
|
# if ':' in ile_historii:
|
|
# _, _, ile_historii = ile_historii.partition(':')
|
|
# if ':' in ile_slow_kluczowych:
|
|
# _, _, ile_slow_kluczowych = ile_slow_kluczowych.partition(':')
|
|
# if ':' in jak_dluga_plejlista:
|
|
# _, _, jak_dluga_plejlista = jak_dluga_plejlista.partition(':')
|
|
try:
|
|
global MUZYKA_MOJEGO_LUDU_HISTORIA # pylint: disable=global-statement
|
|
global MUZYKA_MOJEGO_LUDU_SLOWA_KLUCZOWE # pylint: disable=global-statement
|
|
global MUZYKA_MOJEGO_LUDU_PLAJLISTA # pylint: disable=global-statement
|
|
self.logger.info(
|
|
"Długość historii wyszukiwania: %s\n Ilość słów kluczowych: %s\n Długość plejlisty do wygenerowanie: %s",
|
|
MUZYKA_MOJEGO_LUDU_HISTORIA,
|
|
MUZYKA_MOJEGO_LUDU_SLOWA_KLUCZOWE,
|
|
MUZYKA_MOJEGO_LUDU_PLAJLISTA,
|
|
)
|
|
ctx.send(
|
|
f"Dotychczasowe wartośći:\n Długość historii wyszukiwania: {MUZYKA_MOJEGO_LUDU_HISTORIA}\n Ilość słów kluczowych: {MUZYKA_MOJEGO_LUDU_SLOWA_KLUCZOWE}\n Długość plejlisty do wygenerowanie:{MUZYKA_MOJEGO_LUDU_PLAJLISTA}"
|
|
)
|
|
MUZYKA_MOJEGO_LUDU_HISTORIA = ile_historii
|
|
MUZYKA_MOJEGO_LUDU_SLOWA_KLUCZOWE = ile_slow_kluczowych
|
|
MUZYKA_MOJEGO_LUDU_PLAJLISTA = jak_dluga_plejlista
|
|
self.logger.info(
|
|
"Długość historii wyszukiwania: %s\n Ilość słów kluczowych: %s\n Długość plejlisty do wygenerowanie: %s",
|
|
MUZYKA_MOJEGO_LUDU_HISTORIA,
|
|
MUZYKA_MOJEGO_LUDU_SLOWA_KLUCZOWE,
|
|
MUZYKA_MOJEGO_LUDU_PLAJLISTA,
|
|
)
|
|
self.ctx.send(
|
|
f"Zmienione wartośći:\n Długość historii wyszukiwania: {MUZYKA_MOJEGO_LUDU_HISTORIA}\n Ilość słów kluczowych: {MUZYKA_MOJEGO_LUDU_SLOWA_KLUCZOWE}\n Długość plejlisty do wygenerowanie:{MUZYKA_MOJEGO_LUDU_PLAJLISTA}"
|
|
)
|
|
except discord.ext.commands.errors.BadArgument as exce:
|
|
ctx.send("Spierdalaj")
|
|
self.logger.info(exce)
|
|
|
|
@commands.hybrid_command(
|
|
name="graj_muzyko",
|
|
description="Włącza muzykę na kanale #nocna-zmiana.",
|
|
guild=discord.Object(id=664789470779932693),
|
|
)
|
|
@commands.has_any_role('Nocna Zmiana', 'Jarl', 'Thane' , 'Bartender')
|
|
async def graj_muzyko(self, ctx):
|
|
"""
|
|
Async function named "graj_muzyko" starts music playback on channel "Nocna Zmiana".
|
|
|
|
:param ctx: ctx stands for "context" and is a parameter commonly used in Discord.py commands. It
|
|
represents the context in which the command was invoked, including information such as the message,
|
|
the channel, the server, and the user who invoked the command. This parameter is required in all
|
|
Discord.py commands
|
|
"""
|
|
|
|
self.logger.info("Press play on tape")
|
|
async with ctx.typing():
|
|
global MUZYKA # pylint: disable=global-variable-not-assigned
|
|
MUZYKA["ctx"] = ctx
|
|
await self.connect(ctx=ctx)
|
|
await self.play(ctx=ctx)
|
|
self.logger.info("Press play on tape completed")
|
|
self.check_music.start()
|
|
|
|
async def connect(self, ctx, arg=None):
|
|
"""
|
|
Connect the bot to a voice channel if it is not already connected.
|
|
|
|
:param ctx: ctx is short for context and refers to the context in which the command was invoked. It
|
|
contains information about the message, the channel, the server, and the user who invoked the
|
|
command
|
|
:param arg: The `arg` parameter is an optional argument that can be passed to the `connect`
|
|
function. It is not used in the code snippet provided, but it could potentially be used to specify a
|
|
specific voice channel to connect to
|
|
:return: If the voice client is already connected, the function will return without doing anything.
|
|
If the function successfully connects to the voice channel, it will return a voice channel
|
|
connection object. If it is not possible to connect to the voice channel, the function will log an
|
|
error message and return nothing.
|
|
"""
|
|
if ctx and arg:
|
|
self.logger.info("Ctx and arg defined for connect")
|
|
|
|
if self.bot.voice_clients:
|
|
self.logger.info("Already connected with other client")
|
|
else:
|
|
vc = None
|
|
if ctx.author.voice.channel:
|
|
vc = await ctx.author.voice.channel.connect()
|
|
else:
|
|
voice_channel = self.bot.get_channel(1060349757349974066)
|
|
vc = await voice_channel.connect()
|
|
if not vc:
|
|
self.logger.error("Not possible to connect to voice")
|
|
return
|
|
self.logger.info("Connected to voice")
|
|
|
|
@commands.hybrid_command(
|
|
name="batch_download",
|
|
description="Zaciąga obiekty z pliku",
|
|
guild=discord.Object(id=664789470779932693),
|
|
)
|
|
@commands.has_any_role('Legenda', 'Jarl', 'Thane' , 'Bartender')
|
|
async def batch_download(self, ctx):
|
|
content_type = ctx.message.attachments[0].content_type
|
|
check = re.search("text\/plain; *charset=(.*)", content_type, re.IGNORECASE)
|
|
await ctx.reply("Kurwa. Aleś mi roboty narobił... No nic. Ku radości. Skal!")
|
|
async with ctx.typing():
|
|
if check:
|
|
global MUZYKA # pylint: disable=global-variable-not-assigned
|
|
file_bytes = await ctx.message.attachments[0].read()
|
|
text = file_bytes.decode(encoding=check.group(1))
|
|
self.logger.info(text)
|
|
lines = text.split("\n")
|
|
for link in lines:
|
|
link = link.strip()
|
|
self.logger.info(link)
|
|
pat = r"^https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b(?:[-a-zA-Z0-9()@:%_\+.~#?&\/=]*)$"
|
|
self.logger.info("Verification")
|
|
if re.match(pat, link) and (
|
|
re.match(".*youtube.*", link) or re.match(".*youtu.be.*", link)
|
|
):
|
|
self.logger.info("%s to link do jutuba", link)
|
|
dir_path, files = await music_functions.get_file(
|
|
ctx, "Youtube", link
|
|
)
|
|
if files:
|
|
for file_iter in files:
|
|
global MUZYKA # pylint: disable=global-variable-not-assigned
|
|
MUZYKA["queue"].insert(0, file_iter)
|
|
music_functions.MUSIC_FILE_LIST.update_file_list(
|
|
file_iter
|
|
)
|
|
MUZYKA["requester"].insert(0, ctx.author)
|
|
await ctx.send(f"Dodałem do listy {file_iter}")
|
|
self.logger.info("Jutub udany")
|
|
|
|
elif re.match(pat, link) and re.match(".*spotify.*", link):
|
|
self.logger.info("%s to link do spotify", link)
|
|
dir_path, files = await music_functions.get_file(
|
|
ctx, "Spotify", link
|
|
)
|
|
if platform == "win32":
|
|
separator = "\\"
|
|
else:
|
|
separator = "/"
|
|
for file in files:
|
|
file_path = (
|
|
dir_path
|
|
+ separator
|
|
+ file["artist"]
|
|
+ " - "
|
|
+ file["name"]
|
|
+ ".mp3"
|
|
)
|
|
|
|
MUZYKA["queue"].insert(
|
|
0,
|
|
dir_path
|
|
+ separator
|
|
+ file["artist"]
|
|
+ " - "
|
|
+ file["name"]
|
|
+ ".mp3",
|
|
)
|
|
MUZYKA["requester"].insert(0, ctx.author)
|
|
music_functions.MUSIC_FILE_LIST.update_file_list(file_path)
|
|
await ctx.send(
|
|
f"Dodałem do listy {dir_path}{file['artist']} - + {file['name']}.mp3"
|
|
)
|
|
self.logger.info("Spotifaj udany")
|
|
|
|
elif re.match(pat, link):
|
|
self.logger.info("%s to link do czegos", link)
|
|
sciezka, files = await music_functions.get_file(
|
|
ctx, "Pornol", link
|
|
)
|
|
if files:
|
|
self.logger.info("Pornol udany")
|
|
await ctx.send(
|
|
f"Jest w tajnym archiwum pod adresem{sciezka})"
|
|
)
|
|
|
|
else:
|
|
self.logger.info("Spierdalaj")
|
|
self.logger.info(link)
|
|
await ctx.message.reply("Spierdalaj")
|
|
else:
|
|
self.logger.info(content_type)
|
|
self.logger.info("Spierdalaj")
|
|
await ctx.message.reply("Spierdalaj")
|
|
|
|
async def disconnect(self, ctx):
|
|
"""
|
|
Asynchronous Python function that disconnects the voice client if it is connected and
|
|
logs a message if the context is defined.
|
|
|
|
:param ctx: ctx is short for context and refers to the context in which a command is being executed.
|
|
It contains information about the message, the user who sent the message, the channel the message
|
|
was sent in, and more. In this case, the `disconnect` function is likely being called as a command
|
|
in
|
|
"""
|
|
if ctx:
|
|
self.logger.info("Ctx defined for disconnect")
|
|
if self.bot.voice_clients:
|
|
voice_client = self.bot.voice_clients[0]
|
|
if voice_client.is_connected():
|
|
await voice_client.disconnect()
|
|
|
|
async def play(self, ctx, zamawial=None, arg=None):
|
|
"""
|
|
Play a music file, retrieve metadata about the file, and send a
|
|
message to a Discord channel with information about the song being played.
|
|
|
|
:param ctx: The "ctx" parameter is a context object that contains information about the current
|
|
Discord command invocation, such as the message, the channel, and the user who invoked the command.
|
|
It is passed to the function automatically by the Discord.py library
|
|
:param zamawial: The parameter `zamawial` is a variable that stores the user who requested the song
|
|
to be played. It is an optional parameter and can be None if no user requested the song
|
|
:param arg: The `arg` parameter is an optional argument that can be passed to the `play` function.
|
|
It is not used in the code provided, so its purpose is unclear without additional context
|
|
"""
|
|
# TODO: Uzupełnianie metadanych. Jeśli ich nie ma sprawdzamy nazwę (w sposób inteligentny - czyli jeśli składa się z samych cyfr i/lub słowa track to sprawdzić album w sensie folder)
|
|
# TODO: Jeśli w metadanych jest tylko "audiotrack" i "album" też po
|
|
# folderze. Jeśli są niekompletne uzupełnić dalej.
|
|
self.logger.info("Play procedure")
|
|
if arg:
|
|
self.logger.info("Arg defined for play")
|
|
|
|
file_to_play = None
|
|
voice_client = self.bot.voice_clients[0]
|
|
if not self.bot.voice_clients:
|
|
voice_client = self.bot.voice_clients[0]
|
|
await self.connect(ctx)
|
|
if MUZYKA["queue"]:
|
|
file_to_play = MUZYKA["queue"].pop()
|
|
zamawial = MUZYKA["requester"].pop()
|
|
self.logger.info("Muzyka z listy zamówień")
|
|
else:
|
|
# trunk-ignore(bandit/B311)
|
|
index = random.randint(
|
|
0, len(music_functions.MUSIC_FILE_LIST.get_file_list()) - 1
|
|
)
|
|
file_to_play = music_functions.MUSIC_FILE_LIST.get_file_list()[index]
|
|
self.logger.info("Muzyka losowo")
|
|
|
|
self.logger.info(file_to_play)
|
|
metadata = eyed3.load(file_to_play)
|
|
query = None
|
|
temp = file_to_play.split(SEPARATOR_FILE_PATH)[-1]
|
|
kawalek = f"Zagram teraz kawalek {temp} z prywatnej kolekcji Hammera."
|
|
if metadata:
|
|
if metadata.tag:
|
|
if metadata.tag.title:
|
|
query = f"Opowiedz mi o kawałku {metadata.tag.title}"
|
|
kawalek = f"Zagram teraz kawalek {metadata.tag.title}"
|
|
if metadata.tag.artist:
|
|
query += f" wykonawcy {metadata.tag.artist}"
|
|
kawalek += f" wykonawcy {metadata.tag.artist}"
|
|
if metadata.tag.album:
|
|
query += f" z albumu {metadata.tag.album}"
|
|
kawalek += f" z albumu {metadata.tag.album}"
|
|
kawalek += " z prywatnej kolekcji Hammera."
|
|
if zamawial:
|
|
kawalek += f"Na specjalne życzenie <@{zamawial.id}>."
|
|
await ctx.send(kawalek)
|
|
|
|
voice_client.play(
|
|
discord.PCMVolumeTransformer(
|
|
discord.FFmpegPCMAudio(source=file_to_play), volume=0.3
|
|
)
|
|
) # NIE DOTYKAC POKRĘTŁA GŁOŚNOŚCI!!!!
|
|
if query:
|
|
self.logger.debug("Zapytanie do openai")
|
|
self.logger.debug(query)
|
|
vykidailo = False
|
|
bartender = False
|
|
for role in ctx.message.author.roles:
|
|
if role.name == "Vykidailo":
|
|
vykidailo = True
|
|
if role.name == "Bartender":
|
|
bartender = True
|
|
if ctx.message.author.nick:
|
|
username = ctx.message.author.nick
|
|
else:
|
|
username = ctx.message.author.name
|
|
global MESSAGE_TABLE_MUZYKA # pylint: disable=global-statement
|
|
result, MESSAGE_TABLE_MUZYKA = await handle_response(
|
|
query, vykidailo, bartender, MESSAGE_TABLE_MUZYKA, username, "MUSIC"
|
|
)
|
|
self.logger.debug("Obecna historia czatu: %s", MESSAGE_TABLE_MUZYKA)
|
|
if len(result) < 1500:
|
|
await ctx.send(result)
|
|
else:
|
|
while len(result) > 1500:
|
|
await ctx.send(result[:1500])
|
|
result = result[1500:]
|
|
|
|
|
|
async def setup(bot):
|
|
logger = logging.getLogger("discord")
|
|
await music_functions.MUSIC_FILE_LIST.refresh_file_list(bot)
|
|
logger.info("Playlist generation")
|
|
await bot.add_cog(MusicModule(bot, "discord"))
|
|
logger.info("Loading music commands module done")
|