Files
conjurer/bot.py
T
2024-04-10 15:04:13 +02:00

1279 lines
48 KiB
Python

# This Python file uses the following encoding: utf-8
#pylint: disable=too-many-lines
#pylint: disable=line-too-long
'''
Docstring
'''
# *=========================================== Standard Library Imports
import os
import json
import re
import netrc
import logging
from logging import handlers
from datetime import datetime
import sys
from sys import platform
from platform import uname
import io
import random
import asyncio
from pathlib import PurePath
from pathlib import Path
import shutil
# *==============Imported libraries
import pdf2image
import numpy as np
import PyPDF2
import openai
import requests
import eyed3
import spotipy
from spotipy.oauth2 import SpotifyClientCredentials
import discord
from discord.ext import commands
from spotify_dl import spotify
from spotify_dl import youtube as youtube_download
import yt_dlp
# *=========================================== Predefines
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
master_timeout = datetime.now()
INITIAL_TIME_WAIT = 5
MUZYKA = {"playing": False, "ctx": None, "queue": [], "requestor": []}
LOGFILE = ""
NETRC_FILE = ""
MUSIC_FOLDER = ""
MEMORY_FIVE_SIARA = ""
MEMORY_FIVE_MUZYKA = ""
SETTINGS_FILE = ""
ENCODING = ""
GRAPHICS_PATH = ""
# *=========================================== Platform Specific Predefines
if platform in("linux","linux2"):
if "microsoft-standard" in uname().release:
LOGFILE = "/home/pi/Conjurer/discord.log"
MEMORY_FIVE_SIARA = "/home/pi/Conjurer/pamiec.json"
MEMORY_FIVE_MUZYKA = "/home/pi/Conjurer/pamiec_muzyki.json"
MUSIC_FOLDER = "/home/pi/RetroPie/mp3/"
SETTINGS_FILE = "/home/pi/Conjurer/settings.json"
NETRC_FILE = "/home/pi/.netrc"
LOGSTORE = "/home/pi/RetroPie/logs/"
ACCIDENT_LOG = "/home/pi/Conjurer/accident_log.json"
ENCODING = "utf-8"
GRAPHICS_PATH = "/home/pi/RetroPie/Conjurer_graphics/"
else:
LOGFILE = "/home/pi/Conjurer/discord.log"
MEMORY_FIVE_SIARA = "/home/pi/Conjurer/pamiec.json"
MEMORY_FIVE_MUZYKA = "/home/pi/Conjurer/pamiec_muzyki.json"
MUSIC_FOLDER = "/home/pi/RetroPie/mp3/"
SETTINGS_FILE = "/home/pi/Conjurer/settings.json"
NETRC_FILE = "/home/pi/.netrc"
LOGSTORE = "/home/pi/RetroPie/logs/"
ACCIDENT_LOG = "/home/pi/Conjurer/accident_log.json"
ENCODING = "utf-8"
GRAPHICS_PATH = "/home/pi/RetroPie/Conjurer_graphics/"
elif platform == "win32":
LOGFILE = "discord.log"
MEMORY_FIVE_SIARA = "pamiec.json"
MEMORY_FIVE_MUZYKA = "pamiec_muzyki.json"
MUSIC_FOLDER = "G:\\Muzyka\\"
SETTINGS_FILE = "settings.json"
NETRC_FILE = "C:\\Users\\mtusz\\.netrc"
LOGSTORE = "C:\\Users\\mtusz\\OneDrive\\Pulpit\\Conjurer\\logs\\"
ACCIDENT_LOG = "accident_log.json"
ENCODING = "cp1250"
# *=========================================== Keys
netrc = netrc.netrc(NETRC_FILE)
REMOTE_HOST_NAME = "discord"
authTokens = netrc.authenticators(REMOTE_HOST_NAME)
TOKEN = authTokens[2]
REMOTE_HOST_NAME = "openai"
authTokens = netrc.authenticators(REMOTE_HOST_NAME)
openai.api_key = authTokens[2]
REMOTE_HOST_NAME = "spotipy"
authTokens = netrc.authenticators(REMOTE_HOST_NAME)
spotify_ctrl = spotipy.Spotify(
client_credentials_manager=SpotifyClientCredentials(
client_id=authTokens[0],
client_secret=authTokens[2],
)
)
# *=========================================== Initializations
intents = discord.Intents.default()
intents.message_content = True
intents.typing = True
intents.presences = True
intents.members = True
intents.messages = True
intents.voice_states = True
logger = logging.getLogger("discord")
logger.setLevel(logging.DEBUG)
handler = handlers.RotatingFileHandler(
filename=LOGFILE,
encoding=ENCODING,
mode="a",
maxBytes=6 * 1024 * 1024,
backupCount=6,
)
handler.setFormatter(formatter)
logger.addHandler(handler)
random.seed()
logger.debug(platform)
logger.info("Playlist generation")
# *=========================================== Load Data files
music_file_list = []
for mp3_item in Path.glob(Path(MUSIC_FOLDER), "**/*.mp3"):
temp_music_file = mp3_item.as_posix()
if platform == "win32":
temp_music_file = temp_music_file.replace("/", "\\")
music_file_list.append(temp_music_file)
with open(MEMORY_FIVE_SIARA, "r+", encoding=ENCODING) as temp_memory_file:
# First we load existing data into a dict.
MESSAGE_TABLE = json.load(temp_memory_file)
with open(MEMORY_FIVE_MUZYKA, "r+", encoding=ENCODING) as temp_music_memory_file:
# First we load existing data into a dict.
message_table_muzyka = json.load(temp_music_memory_file)
with open(SETTINGS_FILE,"r",encoding=ENCODING) as f_settings_file:
data = json.load(f_settings_file)
word_reactions = data["word_reactions"]
historia_fabryczki = data["fabryczka"]
for key in word_reactions:
word_reactions[key][2] = datetime.now()
# *=========================================== Create Client
client = commands.Bot(intents=intents, command_prefix="$")
# *=========================================== Define Events
@client.event
async def on_ready():
"""_summary_
"""
logger.debug("%s has connected to Discord!", client.user)
await client.change_presence(activity=discord.Game(name="Axe Throwing Darts"))
await client.tree.sync()
#await tree.sync(guild=discord.Object(id=Your guild id))
await check()
@client.event
async def on_message(message):
"""_summary_
Args:
message (_type_): _description_
"""
vykidailo = False
channel = None
if message.author == client.user:
return
if isinstance(message.author, discord.Member):
for role in message.author.roles:
if role.name == "Vykidailo":
vykidailo = True
if ("Conjurer Śpij Słodko Aniołku" in message.content) and vykidailo:
sys.exit()
# kanal bez bota
if message.channel.id == 1095985579147141202:
return
# wentylacja
if message.channel.id == 1083804024173764739:
return
# legendy
if message.channel.id == 1084448332841230388:
return
# interrogation booth
if message.channel.id == 1111625221171052595:
return
if isinstance(message.channel, discord.DMChannel):
channel = client.get_channel(1064888712565100614)
await channel.send("Słyszałem ja żem że: " + message.content)
else:
channel = message.channel
await client.process_commands(message)
# TODO: wpiac jego reakcje we framework chatu GPT
message.content = message.content.lower()
tdelta = datetime.now() - master_timeout
tdelta = tdelta.total_seconds()
if "opowiedz o fabryczce" in message.content:
await message.reply(historia_fabryczki)
if "opowiedz mi o fabryczce" in message.content:
await message.reply(historia_fabryczki)
if tdelta > INITIAL_TIME_WAIT:
for word in word_reactions:
if re.search(r"\b" + word + r"\b", message.content):
tdelta = datetime.now() - word_reactions[word][2]
tdelta = tdelta.total_seconds()
security_clearance = word_reactions[word][4]
reaction = word_reactions[word][3]
if tdelta > word_reactions[word][1]:
# TODO: to zrobic reactiony
logger.info("Ping z procedury reakcji")
if reaction:
emoji = client.get_emoji(word_reactions[word][0])
await message.add_reaction(emoji)
elif security_clearance and vykidailo:
await message.reply(word_reactions[word][0])
elif not security_clearance:
await message.reply(word_reactions[word][0])
word_reactions[word][2] = datetime.now()
# TODO: drobne literówki, mentiony, spacja przed dwukropkiem. napraw.
if "conjurer:" in message.content:
async with channel.typing():
logger.debug("Procedura chatu")
message.content = message.content.replace("conjurer: ", "")
prompt = message.content
if message.author.nick:
username = message.author.nick
else:
username = message.author.name
vykidailo = False
bartender = False
for role in message.author.roles:
if role.name == "Vykidailo":
vykidailo = True
if role.name == "Bartender":
bartender = True
global MESSAGE_TABLE # pylint: disable=global-statement
result, MESSAGE_TABLE = await handle_response(
prompt, vykidailo, bartender, MESSAGE_TABLE, username, False
)
await message.reply(result)
if "imaginuje sobie:" in message.content:
async with channel.typing():
logger.info("Poczatek procedury obrazkowej")
message.content = message.content.replace("imaginuje sobie: ", "")
logger.debug("Wywolanie obrazka: %s", message.content)
response = openai.Image.create(
prompt=message.content, n=1, size="1024x1024"
)
image_url = response["data"][0]["url"]
logger.debug("Wynikowy obrazek pod url: %s",image_url)
response = requests.get(image_url, timeout=360)
temp_file_name = message.content + ".png"
temp_file_name = (
GRAPHICS_PATH+ message.content + ".png"
)
with open(temp_file_name, "wb") as dalle_file:
dalle_file.write(response.content)
logger.info("Koniec procedury obrazkowej.")
fnord = discord.File(temp_file_name, spoiler=False, description=message.content)
await message.reply(file=fnord)
# *=========================================== Define Functions
async def connect(ctx, arg=None):
"""_summary_
Args:
ctx (_type_): _description_
arg (_type_, optional): _description_. Defaults to None.
"""
if ctx and arg:
logger.info("Ctx and arg defined for connect")
voice_channel = client.get_channel(1060349757349974066)
if client.voice_clients:
voice_client = client.voice_clients[0]
if voice_client.is_connected():
return
voice_channel_connection = await voice_channel.connect()
if not voice_channel_connection:
logger.error("Not possible to connect to voice")
logger.info("Connecting to voice")
async def disconnect(ctx):
"""_summary_
Args:
ctx (_type_): _description_
"""
if ctx:
logger.info("Ctx defined for disconnect")
if client.voice_clients:
voice_client = client.voice_clients[0]
if voice_client.is_connected():
await voice_client.disconnect()
async def play(ctx, zamawial=None, arg=None):
"""_summary_
Args:
ctx (_type_): _description_
zamawial (_type_, optional): _description_. Defaults to None.
arg (_type_, optional): _description_. Defaults to None.
"""
# 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.
logger.info("Play procedure")
if arg:
logger.info("Arg defined for play")
file_to_play = None
voice_client = client.voice_clients[0]
if not client.voice_clients:
voice_client = client.voice_clients[0]
await connect(ctx)
if MUZYKA["queue"]:
file_to_play = MUZYKA["queue"].pop()
zamawial = MUZYKA["requestor"].pop()
else:
index = random.randint(0, len(music_file_list) - 1)
file_to_play = music_file_list[index]
logger.debug(file_to_play)
metadata = eyed3.load(file_to_play)
query = None
separator = None
if platform == "linux" or platform == "linux2":
separator = "/"
elif platform == "win32":
separator = "\\"
temp = file_to_play.split(separator)[-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:
logger.debug("Zapytanie do openai")
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 # pylint: disable=global-statement
result, MESSAGE_TABLE = await handle_response(
query, vykidailo, bartender, message_table_muzyka, username, True
)
logger.debug("Obecna historia czatu: %s",message_table_muzyka)
await ctx.send(result)
async def check():
"""_summary_
"""
while True:
# TODO: Tu dołożyć skanowanie rozmiaru pliku logowania oraz plików pamięci i przenoszenie ich na większy dysk.
# TODO: Dodać typing i dać znać że wykonuje operacje porządkowania Baru (zamiata, układa szklanki itp.)
# TODO: dlaczego sie tu wypierdala
if client.voice_clients:
voice_client = client.voice_clients[0]
if voice_client.is_connected():
while MUZYKA["playing"] and voice_client.is_connected():
if (
voice_client
and not voice_client.is_playing()
and not voice_client.is_paused()
):
await play(MUZYKA["ctx"], MUZYKA["requestor"])
await asyncio.sleep(0.1)
if os.path.getsize(LOGFILE) > 600000:
shutil.copyfile(LOGFILE, f"{LOGSTORE}discord{datetime.now()}")
logger.info("Log rollover")
handler.doRollover()
if os.path.getsize(MEMORY_FIVE_MUZYKA) > 300000:
channel = client.get_channel(1062047571557744721)
await channel.send(
"*Conjurer porządkuje bar, wypala szklanki do czysta miotaczem płomieni ze swojej zbroi i ogólnie wygląda na zajętego....*"
)
with channel.typing():
path_newfile = f"{LOGSTORE}{MEMORY_FIVE_MUZYKA[:-4]}{datetime.now()}.json"
with open(MEMORY_FIVE_MUZYKA, "r+", encoding=ENCODING) as file_music_memory:
with open(path_newfile, "x", encoding=ENCODING) as new_file:
# First we load existing data into a dict.
file_data = json.load(file_music_memory)
new_data = []
new_data.append(file_data[0])
new_data.extend(file_data[:-20])
file_music_memory.seek(0)
# convert back to json.
new_file.seek(0)
json.dump(new_data, file_music_memory, indent=4)
json.dump(file_data, new_file, indent=4)
await channel.send(
"*Przeciąga się za barem* No dobra - porobione to można dalej pi... *Zauważa spojrzenie Hammera* ...sać powieści o naszym wspaniałym barze SZEFIE!"
)
if os.path.getsize(MEMORY_FIVE_SIARA) > 300000:
path_newfile = "{LOGSTORE}{MEMORY_FIVE_SIARA[:-4]}{datetime.now()}.json"
await channel.send(
"*Conjurer porządkuje bar, ścina lekkim laserem pulsacyjnym powierzchnie baru o grubości kilku mikronów i ogólnie wygląda na zajętego....*"
)
with open(MEMORY_FIVE_SIARA, "r+", encoding=ENCODING) as file:
with open(path_newfile, "x", encoding=ENCODING) as new_file:
# First we load existing data into a dict.
file_data = json.load(file)
new_data = []
new_data.append(file_data[0])
new_data.extend(file_data[:-20])
file.seek(0)
new_file.seek(0)
# convert back to json.
json.dump(new_data, file, indent=4)
json.dump(file_data, new_file, indent=4)
await channel.send(
"*Przeciąga się za barem* No dobra - porobione to można dalej pi... *Zauważa spojrzenie Hammera* eprzyć o głupotach z klientami... Szefie... *Bierze 'ukradkowy' łyk z piersiówki*"
)
await asyncio.sleep(60)
async def handle_response(prompt, vykidailo, bartender, history, username, music):
"""_summary_
Args:
prompt (_type_): _description_
vykidailo (_type_): _description_
bartender (_type_): _description_
history (_type_): _description_
username (_type_): _description_
music (_type_): _description_
Returns:
_type_: _description_
"""
# TODO: Wykrywać "Pracuję nad odpowiedzią i tego typu rzeczy"
logger.info("Wywolanie procedury openai z promptem: %s", prompt)
temp = {"role": "user", "content": username + ":" + prompt}
if vykidailo or bartender:
logger.info("Administrator coś chciał")
history.append(temp)
if music:
with open(MEMORY_FIVE_MUZYKA, "r+", encoding=ENCODING) as file_music_memory:
# First we load existing data into a dict.
file_data = json.load(file_music_memory)
# Join new_data with file_data inside emp_details
file_data.append(temp)
file_music_memory.seek(0)
# convert back to json.
json.dump(file_data, file_music_memory, indent=4)
else:
with open(MEMORY_FIVE_SIARA, "r+", encoding=ENCODING) as file_memory:
# First we load existing data into a dict.
file_data = json.load(file_memory)
# Join new_data with file_data inside emp_details
file_data.append(temp)
file_memory.seek(0)
# convert back to json.
json.dump(file_data, file_memory, indent=4)
history = []
# * append bo pierwszy index
# * extend bo 20 ostatnich
if music:
history.append(message_table_muzyka[0])
history.extend(message_table_muzyka[-20:])
else:
history.append(MESSAGE_TABLE[0])
history.extend(MESSAGE_TABLE[-20:])
logger.info("Historia wysłana:")
logger.debug(history)
response = await openai.ChatCompletion.acreate(
model="gpt-3.5-turbo", messages=history
)
await asyncio.sleep(10)
result = ""
logger.debug("Odpowiedzi")
logger.debug(response.choices)
for choice in response.choices:
result += choice.message.content
logger.info("Sformatowane odpowiedzi")
logger.info(result)
temp = {"role": "assistant", "content": result}
history.append(temp)
if music:
with open(MEMORY_FIVE_MUZYKA, "r+", encoding=ENCODING) as file:
# First we load existing data into a dict.
file_data = json.load(file)
# Join new_data with file_data inside emp_details
file_data.append(temp)
# Sets file's current position at offset.
file.seek(0)
# convert back to json.
json.dump(file_data, file, indent=4)
else:
with open(MEMORY_FIVE_SIARA, "r+",encoding=ENCODING) as file:
# First we load existing data into a dict.
file_data = json.load(file)
# Join new_data with file_data inside emp_details
file_data.append(temp)
# Sets file's current position at offset.
file.seek(0)
# convert back to json.
json.dump(file_data, file, indent=4)
return result, MESSAGE_TABLE
async def get_file(ctx, source, link):
"""_summary_
Args:
ctx (_type_): _description_
source (_type_): _description_
link (_type_): _description_
Returns:
_type_: _description_
"""
item_id = None
item_type = None
file_list = {}
if source == "Spotify":
dir_path = None
item_type, item_id = spotify.parse_spotify_url(link)
if item_id:
file_list = spotify.fetch_tracks(spotify_ctrl, item_type, link)
directory_name = spotify.get_item_name(spotify_ctrl, item_type, item_id)
url_data = {"urls": []}
url_dict = {}
url_dict["save_path"] = Path(
PurePath.joinpath(Path(MUSIC_FOLDER), Path(directory_name))
)
url_dict["save_path"].mkdir(parents=True, exist_ok=True)
url_dict["songs"] = file_list
url_data["urls"].append(url_dict.copy())
file_name_f = youtube_download.default_filename
youtube_download.download_songs(
songs=url_data,
output_dir=MUSIC_FOLDER,
format_str="bestaudio/best",
skip_mp3=False,
keep_playlist_order=False,
no_overwrites=True,
remove_trailing_tracks="no",
use_sponsorblock="yes",
file_name_f=file_name_f,
multi_core=0,
proxy="",
)
dir_path = (url_dict["save_path"].resolve()).as_posix()
if platform == "win32":
dir_path = dir_path.replace("/", "\\")
return dir_path, file_list
else:
await ctx.send(
"No se jaja chyba robisz, Ty byś spotifaja nie poznawszy jakby z krzaków wyskoczył i w dupę kopnął. Plejlista, kawałek albo album prosze."
)
logger.error("Wrong link provided spotify: %s",link)
elif source == "Youtube":
link_ok = False
pat = r"^https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b(?:[-a-zA-Z0-9()@:%_\+.~#?&\/=]*)$"
if re.match(pat, link) and re.match(".*youtube.*", link):
link_ok = True
if link_ok:
dir_path = ""
file_list = []
query = link
sponsorblock_postprocessor = [
{
"key": "SponsorBlock",
"categories": ["skip_non_music_sections"],
},
{
"key": "ModifyChapters",
"remove_sponsor_segments": ["music_offtopic"],
"force_keyframes": True,
},
]
if platform == "win32":
dir_path = "G:\\Muzyka\\Youtube"
else:
dir_path = "/home/pi/RetroPie/mp3/Youtube"
ydl_opts = {
"proxy": "",
"default_search": "ytsearch",
"format": "bestaudio/best",
"postprocessors": sponsorblock_postprocessor,
"noplaylist": True,
"no_color": False,
"paths": {"home": dir_path},
}
mp3_postprocess_opts = {
"key": "FFmpegExtractAudio",
"preferredcodec": "mp3",
"preferredquality": "192",
}
ydl_opts["postprocessors"].append(mp3_postprocess_opts.copy())
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
try:
ydl.download([query])
except Exception as exce: #pylint: disable=broad-exception-caught
logger.error(exce)
logger.info(
"Failed to download %s, make sure yt_dlp is up to date", link
)
extract = re.search("v=(...........)[&,$]*", link)
ident = extract.group(1)
for item in Path.glob(Path(dir_path), "**/*.mp3"):
file = item.as_posix()
if platform == "win32":
file = file.replace("/", "\\")
if re.match(".*" + ident + ".*", file):
file_list.append(file)
return dir_path, file_list
else:
await ctx.send(
"No se jaja chyba robisz, Ty byś jutuba nie poznawszy jakby z krzaków wyskoczył i w dupę kopnął. Jutuba to nie tuba którą sobie można gdzieś wsadzić."
)
logger.error("Wrong link provided youtube: %s",link)
return "", None
# define an asynchronous generator
async def async_iterator_generator(range_of_iterable):
# pylint: disable=pointless-string-statement
"""_summary_
Args:
range (_type_): _description_
Yields:
_type_: _description_
"""
# normal loop
for i in range_of_iterable:
# yield the result
yield i
''' Alternatywna wersja przerobienia fora na asynchroniczny
# traverse the iterable of awaitables
for item in coros:
# await and get the result from the awaitable
result = await item
# report the results
print(result)
'''
async def wyszukaj(ctx, how_many=0):
"""_summary_
Args:
ctx (_type_): _description_
how_many (int, optional): _description_. Defaults to 0.
Returns:
_type_: _description_
"""
# TODO: Potem dorobić wyszukiwania po kawałkach słów i sieć neuronową z możliwością wyrażenia opinii o dopasowaniu.
word_list = ctx.message.content.split()
logger.info("Wyszukuje")
search_weight = []
for _ in range(len(music_file_list)):
search_weight.append((0, ""))
time_start = datetime.now()
if int(how_many) > 0:
skip_start = 2
else:
skip_start = 1
for word in word_list[skip_start:]:
token_weight = len(word)
logger.info("Słowo kluczowe: %s",word)
itr = 0
for file in music_file_list:
if platform == "win32":
file = file.split("\\")
else:
file = file.split("/")
char_remove = [
".",
"^",
"$",
"*",
"+",
"?",
"{",
"}",
"[",
"]",
"\\",
"|",
"(",
")",
"!",
",",
"-",
":",
"mp3",
]
all_words = []
for f_iter in file:
for char in char_remove:
f_iter = f_iter.replace(char, "")
tmp = f_iter.split()
all_words.extend(tmp)
pingu = 1
pattern_len = len(all_words)
if platform == "win32":
skip = 2
else:
skip = 4
matched_times = 1
for itm in all_words[skip:]:
pingu += 1
pattern = ".*" + word + ".*"
if re.match(pattern, itm, re.IGNORECASE):
temp_weight = (
search_weight[itr][0]
+ (token_weight + (pingu**1.5) / pattern_len) / matched_times
)
search_weight[itr] = temp_weight, music_file_list[itr]
matched_times += 1
itr += 1
logger.info(
"Stworzylem tablice wag zajęło mi to %s",datetime.now() - time_start)
time_start = datetime.now()
item_to_search = await max_weight(search_weight)
itr = 0
if item_to_search == 0:
return None
not_found = True
return_list = []
if int(how_many) <= 0:
logger.info("Jeden plik do zagrania")
while not_found:
if search_weight[itr][0] == item_to_search:
return_list.append(search_weight[itr])
return return_list
itr += 1
else:
logger.info("Wiele plików do zagrania")
search_weight.sort(key=lambda x: x[0], reverse=True)
return_list.extend(search_weight[: int(how_many)])
return return_list
async def max_weight(lista):
"""_summary_
Args:
list (_type_): _description_
Returns:
_type_: _description_
"""
maximum_weight = 0
for iterator in lista:
if iterator[0] > maximum_weight:
maximum_weight = iterator[0]
return maximum_weight
# *=========================================== Define Commands
@client.hybrid_command(name = "dej_co_ze_spotifaja", description = "Podaj link do spotify - sciagnie i doda muzyke", guild=discord.Object(id=664789470779932693))
async def dej_co_ze_spotifaja(ctx):
"""_summary_
Args:
ctx (_type_): _description_
"""
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 get_file(ctx, "Spotify", item)
if platform == "win32":
separator = "\\"
else:
separator = "/"
for file in files:
global MUZYKA #pylint: disable=global-variable-not-assigned
MUZYKA["queue"].insert(
0,
dir_path
+ separator
+ file["artist"]
+ " - "
+ file["name"]
+ ".mp3",
)
MUZYKA["requestor"].insert(0, ctx.author)
music_file_list.append(file)
await ctx.send(
f"Dodałem do listy {dir_path}{file['artist']} - + {file['name']}.mp3"
)
logger.info("Spotifaj udany")
@client.hybrid_command(name = "dej_co_z_jutuba", description = "Podaj link do youtube - sciagnie i doda muzyke",guild=discord.Object(id=664789470779932693))
async def dej_co_z_jutuba(ctx):
"""_summary_
Args:
ctx (_type_): _description_
"""
await ctx.send("Dej mnie chwilkę")
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 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_file_list.append(file_iter)
MUZYKA["requestor"].insert(0, ctx.author)
await ctx.send(f"Dodałem do listy {file_iter}")
logger.info("Jutub udany")
@client.hybrid_command(name = "update_banlist", description = "Jeśli nie wiesz jak użyć tej komendy to nawet nie próbuj",guild=discord.Object(id=664789470779932693))
async def update_banlist(ctx):
"""_summary_
Args:
ctx (_type_): _description_
"""
async with ctx.channel.typing():
allowed = False
for role in ctx.author.roles:
if role.name == "Jarl":
allowed = True
if ctx.channel.id != 1102190666827702342:
await ctx.send("Nie wydaje mnie sie")
elif not allowed:
await ctx.send("Idź bo Cię zdziele")
else:
tobancunter = 0
async with ctx.typing():
# 1. get list of users posted on channel for banning
channel = ctx.channel
messages = [message async for message in channel.history(limit=None)]
ids_to_ban = []
for message in messages:
lines = message.content.split("\n")
for line in lines:
match = re.search("\\d{18}", line) #poprawilem backslash na podwojny bo linter sie czepial
if match:
ids_to_ban.append(match.group())
tobancunter += 1
# 2. get list of already banned users for all servers Conjurer has rights to
for guild in client.guilds:
bancunter = 0
logger.info("Serwer: %s",guild)
current_banlist = []
permission = True
try:
async for entry in guild.bans(limit=None):
current_banlist.append(entry.user.id)
bancunter += 1
except: #pylint: disable=bare-except
permission = False
if permission:
# 3. compare lists ban only users on list 2 and not on list 1
cunter_counter = 0
bad_id_cunter_counter = 0
ban_list = np.setdiff1d(ids_to_ban, current_banlist)
for ident in ban_list:
try:
tmp_user = await client.fetch_user(int(ident))
await guild.ban(
tmp_user,
reason="Automatyczna lista banów",
delete_message_seconds=0,
)
cunter_counter += 1
except discord.NotFound:
logger.info(
"Znaleziono uzyszkodnika ktory juz nie ma konta"
)
bad_id_cunter_counter += 1
# 4. return message success/failure - how many banned
await ctx.send(
"Obecnie na serwerze {guild} jest {bancunter} zbanowanych użytkowników. Znaleziono na tym kanale {tobancunter} id użytkowników do zbanowania. Zbanowano {cunter_counter} użytkowników. Na liście jest {bad_id_cunter_counter} użytkowników którzy skasowali już konto"
)
else:
await ctx.send(
f"Nie mam na serwerze {guild} uprawnień do banowania. :()"
)
await ctx.send("Zrobione tak czy inaczej")
@client.hybrid_command(nsfw=True, name = "get_image_sadox", description = "Wyświetla losową stronę z losowego komiksu FanSadox. Bardzo NSFW.",guild=discord.Object(id=664789470779932693))
async def get_image_sadox(ctx):
"""_summary_
Args:
ctx (_type_): _description_
"""
logger.info("Get sadox")
channel = ctx.message.channel
async with channel.typing():
dir_path_sadox = ""
# select random file
if platform == "linux" or platform == "linux2":
dir_path_sadox = "/home/pi/RetroPie/Fansadox/"
elif platform == "win32":
dir_path_sadox = "C:\\Users\\mtusz\\OneDrive\\Dokumenty\\Fansadox\\"
res = []
# Iterate directory
for path in os.listdir(dir_path_sadox):
# check if current path is a file
if os.path.isfile(os.path.join(dir_path_sadox, path)):
res.append(path)
filename = res[random.randrange(0, len(res) - 1)]
# select random page
file = open(dir_path_sadox + filename, "rb")
readpdf = PyPDF2.PdfReader(file)
totalpages = len(readpdf.pages)
page = random.randrange(1, totalpages)
# convert page to image
image = pdf2image.convert_from_path(
dir_path_sadox + filename, first_page=page, last_page=page
)
byte_io_stream = io.BytesIO()
image[0].save(byte_io_stream, "JPEG")
byte_io_stream.seek(0)
byte_io_stream.name = "image.jpg"
file = discord.File(byte_io_stream)
await ctx.send(file=file)
logger.info("Get sadox completed")
@client.hybrid_command(name = "graj_muzyko", description = "Włącza muzykę na kanale #nocna-zmiana.",guild=discord.Object(id=664789470779932693))
async def graj_muzyko(ctx):
"""_summary_
Args:
ctx (_type_): _description_
"""
logger.info("Press play on tape")
async with ctx.typing():
global MUZYKA #pylint: disable = global-variable-not-assigned
MUZYKA["playing"] = True
MUZYKA["ctx"] = ctx
await connect(ctx=ctx)
await play(ctx=ctx)
logger.info("Press play on tape completed")
@client.hybrid_command(name = "cisza", description = "Wyłącza muzykę i czyści plejliste.",guild=discord.Object(id=664789470779932693))
async def cisza(ctx):
"""_summary_
Args:
ctx (_type_): _description_
"""
logger.info("Stop")
global MUZYKA #pylint: disable = global-variable-not-assigned
MUZYKA["playing"] = False
MUZYKA["ctx"] = None
voice_client = client.voice_clients[0]
if voice_client.is_connected():
await disconnect(ctx=ctx)
while MUZYKA["queue"]:
MUZYKA["queue"].pop()
MUZYKA["requestor"].pop()
logger.info("Stop completed")
@client.hybrid_command(name = "dalej", description = "Przerzuca na następny kawałek",guild=discord.Object(id=664789470779932693))
async def dalej(ctx):
"""_summary_
Args:
ctx (_type_): _description_
"""
if ctx:
logger.info("Ctx defined for dalej")
logger.info("Next")
voice_client = client.voice_clients[0]
if voice_client.is_connected():
voice_client.stop()
await play(ctx=ctx)
logger.info("Next completed")
@client.hybrid_command(name = "daj_mi_chwile", description = "Pauzuje",guild=discord.Object(id=664789470779932693))
async def daj_mi_chwile(ctx):
"""_summary_
Args:
ctx (_type_): _description_
"""
if ctx:
logger.info("Ctx defined for pause")
logger.info("Pause")
voice_client = client.voice_clients[0]
if voice_client.is_connected():
voice_client.pause()
logger.info("Pause completed")
@client.hybrid_command(name = "graj_dalej", description = "Odpauzowuje",guild=discord.Object(id=664789470779932693))
async def graj_dalej(ctx):
"""_summary_
Args:
ctx (_type_): _description_
"""
if ctx:
logger.info("Ctx defined for graj_dalej")
logger.info("Unpause")
voice_client = client.voice_clients[0]
if voice_client.is_paused():
voice_client.resume()
logger.info("Unpause completed")
@client.hybrid_command(name = "zagraj_mi_kawalek", description = "Wyszukuje w bibliotece muzycznej Hammera kawałek który ma zostać zagrany",guild=discord.Object(id=664789470779932693))
async def zagraj_mi_kawalek(ctx):
"""_summary_
Args:
ctx (_type_): _description_
"""
async with ctx.typing():
search_time_glob = datetime.now()
logger.info("Zaczynam szukać timestamp %s",datetime.now())
file = await wyszukaj(ctx=ctx)
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["requestor"].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"
)
@client.hybrid_command(name = "zrob_mi_plejliste", description = "Generuje playliste - param1 - dlugosc, potem slowa wyszukiwania",guild=discord.Object(id=664789470779932693))
async def zrob_mi_plejliste(ctx):
"""_summary_
Args:
ctx (_type_): _description_
"""
reply = "Wygenerowana plejlista:\n"
async with ctx.typing():
logger.info("Zaczynam szukać timestamp %s",datetime.now())
search_time_glob = datetime.now()
dlugosc_playlisty = ctx.message.content.split()[1]
file = await wyszukaj(ctx=ctx, how_many=dlugosc_playlisty)
logger.info(
"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["requestor"].insert(0, ctx.author)
metadata = eyed3.load(plik[1])
if metadata.tag.title:
reply += f"{index} {metadata.tag.title}"
else:
reply += "{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"
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)
logger.info("Plejlista zrobiona")
@client.hybrid_command(name = "przytul", description = "Przytul kogoś - daj mention po komendzie :)")
async def przytul(ctx, arg:discord.Member=None):
"""_summary_
Args:
ctx (_type_): _description_
arg (discord.Member, optional): _description_. Defaults to None.
"""
async with ctx.typing():
nieprzytulac = False
for mention in ctx.message.mentions:
for role in mention.roles:
if role.name == "NIEPRZYTULAĆ!":
nieprzytulac = True
if arg and nieprzytulac:
await ctx.send(
f"Żebym ja Ciebie nie przytulił {ctx.message.author.mention}"
)
elif arg:
await ctx.send(
f"Już dobrze.... Już dobrze... Ojej.. Biedactwo... :( *W ułamku sekundy {arg.mention} znajduje sie w duszącym uścisku. Żebra trzeszczą - kilka pęka. Pacnięcia po plecach grożą odbiciem nerek, a głaskanie po głowie powoduje wstrząs mózgu*"
)
else:
await ctx.send(
"Kogo mam przytulić? *Wyłamuje kostki i przeciąga się - jego 200 kilowa sylwetka złożona z samych mięśni świadczy o tym że jest gotowy*"
)
@client.hybrid_command(name = "fabryczka", description = "Historia fabryczki")
async def fabryczka(ctx):
"""_summary_
Args:
ctx (_type_): _description_
"""
await ctx.send(historia_fabryczki)
@client.hybrid_command(name = "chata_hammera", description = "Czas od ostatniego incydentu w AbsinthHammerTimeSpaceContinuum")
async def chata_hammera(ctx):
"""_summary_
Args:
ctx (_type_): _description_
"""
with open(ACCIDENT_LOG, "r+", encoding=ENCODING) as new_file:
# First we load existing data into a dict.
file_data = json.load(new_file)
opis = file_data[-1][0]
czas = datetime.strptime(file_data[-1][1], "%Y-%m-%d %H:%M:%S.%f")
await ctx.send(
f"Komenda mierząca incydenty w Eldritch AbsinthHammerTimeSpaceContinuum.\n Od ostatniego incydentu w chacie Hammera minęło {datetime.now() - czas}. Incydent to: {opis}"
)
@client.hybrid_command(name = "historia_incydentow_u_hammera", description = "Wyswietla liste incydentów które miały miejsce w AbsinthHammerTimeSpaceContinuum.")
async def historia_incydentow_u_hammera(ctx):
"""_summary_
Args:
ctx (_type_): _description_
"""
with open(ACCIDENT_LOG, "r+", encoding=ENCODING) as new_file_accidents:
# First we load existing data into a dict.
file_data = json.load(new_file_accidents)
return_data = "Komenda mierząca incydenty w Eldritch AbsinthHammerTimeSpaceContinuum.\n Historia zarejestrownych incydentów u Hammera:\n"
index = 1
for iter_data in file_data:
opis = iter_data[0]
czas = datetime.strptime(iter_data[1], "%Y-%m-%d %H:%M:%S.%f")
add_data = f"{index}. Opis: {opis} Data: {czas}"
return_data = return_data + add_data + "\n"
index += 1
await ctx.send(return_data)
@client.hybrid_command(name = "reset_the_clock", description = "Resetowanie zegara - dostępne wyłącznie dla Hammera", guild=discord.Object(id=664789470779932693))
async def reset_the_clock(ctx):
"""_summary_
Args:
ctx (_type_): _description_
"""
hammer = False
for role in ctx.message.author.roles:
if role.name == "Bartender":
hammer = True
if hammer:
with open(ACCIDENT_LOG, "r+", encoding=ENCODING) as new_file_accidents:
# First we load existing data into a dict.
file_data = json.load(new_file_accidents)
czas = datetime.strptime(file_data[-1][1], "%Y-%m-%d %H:%M:%S.%f")
opis = ctx.message.content[16:]
accident = accident = [opis, f"{datetime.now()}"]
file_data.append(accident)
new_file_accidents.seek(0)
# convert back to json.
json.dump(file_data, new_file_accidents, indent=4)
await ctx.send(
f"Komenda mierząca incydenty w Eldritch AbsinthHammerTimeSpaceContinuum.\n RESET THE CLOCK. Od ostatniego incydentu w chacie Hammera minęło {czas}. No ale teraz się odpierdoliło: {opis}"
)
else:
await ctx.send(
f"Komenda mierząca incydenty w Eldritch AbsinthHammerTimeSpaceContinuum.\n Gdzie z łapami do zegara? {client.get_user(346956223645614080).mention} coś albo się komuś stało albo zaraz się stanie jak będzie zegar tykał...."
)
#@client.hybrid_command()
async def get_image_stable_diffusion(ctx):
"""_summary_
Args:
ctx (_type_): _description_
"""
if ctx:
pass
#@client.hybrid_command()
async def zagraj_muzyke_mego_ludu(ctx):
"""_summary_
Args:
ctx (_type_): _description_
"""
if ctx:
pass
# *================================== Run
client.run(TOKEN)