From b8df466e6fbd8e976fc6a80d1e139ac4589368f7 Mon Sep 17 00:00:00 2001 From: Polish Hammer Date: Thu, 30 Oct 2025 16:59:12 +0100 Subject: [PATCH] Tag: 1.16 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Intermediate commits (oldest → newest): - moving api key to netrc - New stuff incoming - Manual external audition - Let's get this effin party started - test mic - tst - Test - Test - fix - fx - test - Refactoring step one - Deploy script for after refactor - Fix and upgrade - bg fx - fx - fx - fx - Main refactoring - Deploy script refactor - fx - fx2 - bgfx --- administration_commands.py | 226 +++ ai_commands.py | 234 +++ ai_functions.py | 294 +++ bot.py | 18 +- bot_classes.py | 0 bot_commands.py | 0 bot_functions.py | 0 coach.sex.json | 1707 ----------------- communication_subroutine.py | 75 +- conjurer_musician/radio_conjurer.liq | 8 +- conjurer_musician/test_mic.liq | 23 + constants.py | 137 ++ deploy.sh | 26 +- deploy_music.sh | 2 +- install_main_bot.sh | 11 +- install_music_bot.sh | 9 + librarian_commands.py | 285 +++ music_commands.py | 713 +++++++ music_functions.py | 285 +++ other_commands.py | 191 ++ other_functions.py | 88 + radio_commands.py | 201 ++ requirements_bot copy.txt | 21 + requirements_bot.txt | 5 +- sr_example.py | 229 --- stream_test.py | 55 +- test.py | 20 + test_data_retrieval.py | 26 - test_time.py | 3 +- thin_client.py | 92 + voice_example.py | 47 - ...nition.py => voice_recognition_commands.py | 176 +- 32 files changed, 3056 insertions(+), 2151 deletions(-) create mode 100644 administration_commands.py create mode 100644 ai_commands.py create mode 100644 ai_functions.py delete mode 100644 bot_classes.py delete mode 100644 bot_commands.py delete mode 100644 bot_functions.py delete mode 100644 coach.sex.json create mode 100644 conjurer_musician/test_mic.liq create mode 100644 constants.py create mode 100644 librarian_commands.py create mode 100644 music_commands.py create mode 100644 music_functions.py create mode 100644 other_commands.py create mode 100644 other_functions.py create mode 100644 radio_commands.py create mode 100644 requirements_bot copy.txt delete mode 100644 sr_example.py create mode 100644 test.py delete mode 100644 test_data_retrieval.py create mode 100644 thin_client.py delete mode 100644 voice_example.py rename voice_recognition.py => voice_recognition_commands.py (52%) diff --git a/administration_commands.py b/administration_commands.py new file mode 100644 index 0000000..c480e37 --- /dev/null +++ b/administration_commands.py @@ -0,0 +1,226 @@ +import json +import logging +import os +import random +import re +import shutil +from datetime import datetime + +import discord +import numpy as np +from discord.ext import commands, tasks + +from ai_functions import get_random_cyclic_message +from constants import ENCODING, LOGFILE, LOGSTORE, MEMORY_FIVE_MUZYKA, MEMORY_FIVE_SIARA, LAST_SPONTANEOUS_CALL, TIME_BETWEEN_CALLS + + +class AdministrationModule(commands.Cog): + def __init__(self, bot, logger_name): + self.bot = bot + self.logger = logging.getLogger(logger_name) + + @commands.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(self, ctx): + """ + Update a banlist in a Discord guild from preprovided list in channel. + + :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.channel.typing(): + allowed = False + for role in ctx.author.roles: + if role.name == "Jarl": + allowed = True + + if ctx.channel.id != 1102190666827702342: + # trunk-ignore(codespell/misspelled) + 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, + # trunk-ignore(codespell/misspelled) + ) # 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 self.bot.guilds: + bancunter = 0 + # trunk-ignore(codespell/misspelled) + self.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 BaseException: # pylint: disable=broad-exception-caught + 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 self.bot.fetch_user(int(ident)) + await guild.ban( + tmp_user, + reason="Automatyczna lista banów", + delete_message_seconds=0, + ) + cunter_counter += 1 + except discord.NotFound: + self.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") + + async def archive_channel(self, channel_no): + """ + The function `archive_channel` retrieves messages from a specified channel, processes them, and + saves the data in a JSON file with a timestamp in the filename. + + :param channel_no: The `archive_channel` function you provided seems to be incomplete. It looks like + you are trying to archive messages from a Discord channel into a JSON file + """ + channel = self.bot.get_channel(channel_no) + messages = [message async for message in channel.history(limit=None)] + path_newfile = f"{LOGSTORE}channeldump_{channel_no}_{datetime.now()}.json" + new_data = [] + for message in messages: + new_data.append(message) + with open(path_newfile, "x", encoding=ENCODING) as new_file: + new_file.seek(0) + json.dump(new_data, new_file, indent=4) + + @tasks.loop(seconds=120) + async def check_self(self): + """ + The function `check_data` periodically checks for conditions to send messages and manage log files + in a Discord channel. + """ + # logger.info("Heartbeat of cleanup proc") + channel = self.bot.get_channel(1062047367337095268) + messages = [message async for message in channel.history(limit=1)] + for mess in messages: + channel = mess.channel + if os.path.getsize(LOGFILE) > 60000000: + 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....*" + ) + async with channel.typing(): + shutil.copyfile(LOGFILE, f"{LOGSTORE}discord{datetime.now()}") + self.logger.info("Log rollover") + handlers = self.logger.handlers + for handler in handlers: + if isinstance(handler, logging.handlers.RotatingFileHandler): + handler.doRollover() + 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_MUZYKA) > 3000000: + 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....*" + ) + async with channel.typing(): + path_newfile = f"{LOGSTORE}pamiec_muzyki{datetime.now()}.json" + self.logger.info(path_newfile) + 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.truncate(0) + 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) > 3000000: + path_newfile = f"{LOGSTORE}pamiec_rozmow{datetime.now()}.json" + self.logger.info(path_newfile) + 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.truncate(0) + 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*" + ) + global LAST_SPONTANEOUS_CALL + global TIME_BETWEEN_CALLS + tdelta = datetime.now() - LAST_SPONTANEOUS_CALL + tdelta = tdelta.total_seconds() + if tdelta > TIME_BETWEEN_CALLS: + self.logger.info("Spontaneous call") + # trunk-ignore(bandit/B311) + TIME_BETWEEN_CALLS = random.randint( + 10200, 272800 + ) # temp random, set after each call + self.logger.debug(TIME_BETWEEN_CALLS) + LAST_SPONTANEOUS_CALL = datetime.now() + async with channel.typing(): + message = await get_random_cyclic_message() + self.logger.info("Odpowiedz") + self.logger.info(message) + await channel.send(message) + + +async def setup(bot): + logger = logging.getLogger("discord") + am = AdministrationModule(bot, "discord") + await bot.add_cog(am) + am.check_self.start() + logger.info("Loading administration commands module done") diff --git a/ai_commands.py b/ai_commands.py new file mode 100644 index 0000000..be196f1 --- /dev/null +++ b/ai_commands.py @@ -0,0 +1,234 @@ +# ai command cogs +import logging +import re +import sys +from datetime import datetime + +import discord +import openai +import requests +from discord.ext import commands + +from ai_functions import handle_response +from constants import ( + DATA, + GRAPHICS_PATH, + INITIAL_TIME_WAIT, + MASTER_TIMEOUT, + OPENAICLIENT, +) + + +class Events(commands.Cog): + def __init__(self, bot): + self.bot = bot + self.logger = logging.getLogger("discord") + + @commands.Cog.listener() + async def on_ready(self): + print("Ready!") + print("Logged in as ---->", self.bot.user) + print("ID:", self.bot.user.id) + + @commands.Cog.listener() + async def on_message(self, message): + """ + Handle incoming messages in a Discord server, perform various + checks and actions based on the content and context of the message, and respond accordingly. + + :param message: The message object that is received when a user sends a message in a Discord server + or DM. The code is checking various conditions and performing actions based on the content of the + message and the context in which it was sent. It also includes TODOs for future improvements + :return: The function `on_message` is being returned. + """ + vykidailo = False + channel = None + if message.author == self.bot.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): + if message.author.id == 346956223645614080: + await message.reply("Witam witam") + return + else: + channel = self.bot.get_channel(1064888712565100614) + await channel.send("Słyszałem ja żem że: " + message.content) + return + channel = message.channel + #await self.bot.process_commands(message) #uncomment to bilocate + + message.content = message.content.lower() + + tdelta = datetime.now() - MASTER_TIMEOUT + tdelta = tdelta.total_seconds() + if "opowiedz o fabryczce" in message.content: + await message.reply(DATA["fabryczka"]) + if "opowiedz mi o fabryczce" in message.content: + await message.reply(DATA["fabryczka"]) + + if tdelta > INITIAL_TIME_WAIT: + for word in self.word_reactions: + if re.search(r"\b" + word + r"\b", message.content): + tdelta = datetime.now() - self.word_reactions[word][2] + tdelta = tdelta.total_seconds() + security_clearance = self.word_reactions[word][4] + reaction = self.word_reactions[word][3] + if tdelta > self.word_reactions[word][1]: + # TODO: to zrobic reactiony + self.logger.info("Ping z procedury reakcji") + if reaction: + emoji = self.bot.get_emoji(self.word_reactions[word][0]) + await message.add_reaction(emoji) + elif security_clearance and vykidailo: + await message.reply(self.word_reactions[word][0]) + elif not security_clearance: + await message.reply(self.word_reactions[word][0]) + self.word_reactions[word][2] = datetime.now() + + # TODO: drobne literówki, mentiony, spacja przed dwukropkiem. napraw. + kondziu_mentioned = False + for mention in message.mentions: + if mention == self.bot.user: + kondziu_mentioned = True + + if kondziu_mentioned or "conjurer:" in message.content: + async with channel.typing(): + self.logger.debug("Procedura chatu") + + message.content = message.content.replace("conjurer: ", "") + if message.author.nick: + username = message.author.nick + else: + username = message.author.name + vykidailo = False + bartender = False + if kondziu_mentioned: + prompt = message.clean_content + else: + prompt = message.content + 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, + "CONVERSATION", + ) + + if len(result) < 1500: + await message.reply(result) + else: + while len(result) > 1500: + await message.reply(result[:1500]) + result = result[1500:] + if "imaginuje sobie:" in message.content: + async with channel.typing(): + self.logger.info("Poczatek procedury obrazkowej") + message.content = message.content.replace("imaginuje sobie: ", "") + self.logger.debug("Wywolanie obrazka: %s", message.content) + try: + response = await OPENAICLIENT.images.generate( + model="dall-e-3", + prompt=message.content, + size="1024x1024", + quality="standard", + n=1, + ) + except openai.APITimeoutError as e: + # Handle timeout error, e.g. retry or log + await message.reply( + f"*Kondziu patrzy na terminal, czeka, czeka, czeka,.... Jeszcze chwile czeka Przypierdala w niego pięścią....* Nie mogę się połączyć z Openai spróbuj od nowa. *Na ekranie pojawia się*: {e}" + ) + except openai.APIConnectionError as e: + await message.reply( + f"*Kondziu patrzy na terminal, chwile się zastanawia. Przypierdala w niego pięścią....* Nie mogę się połączyć z Openai. *Na ekranie pojawia się*: {e}" + ) + except openai.BadRequestError as e: + # Handle invalid request error, e.g. validate parameters or log + if message.author.nick: + username = message.author.nick + else: + username = message.author.name + resp, _ = await handle_response( + f"Wytlumacz jakie sa zasady dotyczące treści które możesz generować używając Dalle. Wytłumacz błąd {e} prostym językiem. Przeproś za nadmierną cenzurę. Wytłumacz co mogło być nie tak w prompcie '{message.content}'", + True, + True, + MESSAGE_TABLE, + username, + "RANDOM", + ) + await message.reply( + f"Sorki, cenzura: {resp}. Jak chcesz to są kanały na nudle #sexy-foteczky i #kanal-do-fapania *Na ekranie pojawia się: {e}" + ) + except openai.AuthenticationError as e: + # Handle authentication error, e.g. check credentials or log + await message.reply( + f"*Kondziu patrzy na terminal, chwile się zastanawia. Przypierdala w niego pięścią....* Wołaj szefa - coś się z hasłem zjebało. *Na terminalu pojawia się:* {e}" + ) + except openai.PermissionDeniedError as e: + # Handle permission error, e.g. check scope or log + await message.reply( + ( + f"*Kondziu patrzy na terminal, chwile się zastanawia. Przypierdala w niego pięścią....* Wołaj szefa - coś się z uprawnieniami zjebało. *Na terminalu pojawia się:* {e}" + ) + ) + except openai.RateLimitError as e: + await message.reply( + f"*Kondziu patrzy na terminal* Wołaj szefa. Zapłacić rachunki za AI trzeba. Jak chcesz to się na #zebranie dorzuć. {e}" + ) + except openai.APIError as e: + # Handle API error, e.g. retry or log + await message.reply( + f"*Kondziu nurkuje za bar, terminal wybucha. Przed tobą ląduje pergamin zapisany pięknym gotykiem a na nim*: {e}" + ) + if response: + self.logger.info(response) + image_url = response.data[0].url + image_desc = response.data[0].revised_prompt + self.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) + self.logger.info("Koniec procedury obrazkowej.") + fnord = discord.File( + temp_file_name, spoiler=False, description=message.content + ) + await message.reply(f"{image_desc}", file=fnord) + + +# *=========================================== Define Functions + + +async def setup(bot): + logger = logging.getLogger("discord") + await bot.add_cog(Events(bot)) + logger.info("Loading ai events module done") diff --git a/ai_functions.py b/ai_functions.py new file mode 100644 index 0000000..0e738d7 --- /dev/null +++ b/ai_functions.py @@ -0,0 +1,294 @@ +import asyncio +import json +import logging +import random + +import openai +import tiktoken + +from constants import ( + CYCLIC_WORDS, + ENCODING, + GPT_SETTINGS, + MEMORY_FIVE_MUZYKA, + MEMORY_FIVE_SIARA, + MESSAGE_TABLE, + MESSAGE_TABLE_MUZYKA, + OPENAICLIENT, + WORD_REACTIONS, +) + + +def num_tokens_from_string(message, model): + """ + The function takes a string message and a model as input and returns the number of tokens in the + message according to the given model. + + :param message: A string containing the message or text from which you want to count the number of + tokens + :param model: The model parameter refers to a language model or tokenizer that can be used to + tokenize the input string. It could be a pre-trained model or a custom tokenizer + """ + tokens_per_message = 3 + tokens_per_name = 1 + chat_gpt_encoding = tiktoken.encoding_for_model(model) + + num_tokens = 0 + num_tokens += tokens_per_message + for keys, values in message.items(): + num_tokens += len(chat_gpt_encoding.encode(values)) + if keys == "role": + num_tokens += tokens_per_name + num_tokens += 3 # every reply is primed with <|start|>assistant<|message|> + return num_tokens + + +async def handle_response( + prompt, vykidailo, bartender, history, username, request_type +): + """ + Handle responses by appending them to a history, use OpenAI to + generate a response, and then append the generated response to the history. + + :param prompt: The prompt for the OpenAI chatbot to generate a response to + :param vykidailo: It is a boolean variable that indicates whether the user invoking the function is + an administrator or not + :param bartender: The bartender parameter is a boolean value indicating whether the user making the + request is a bartender or not + :param history: A list containing the conversation history between the user and the assistant + :param username: The username of the user who initiated the conversation + :param music: The "music" parameter is a boolean value that indicates whether the conversation is + related to music or not. If it is True, the conversation history will be stored in a different file + and the response will be generated using a different model + :return: The function `handle_response` returns a tuple containing the `result` and `MESSAGE_TABLE`. + """ + # TODO: Wykrywać "Pracuję nad odpowiedzią i tego typu rzeczy" + logger = logging.getLogger("discord") + 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 request_type == "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) + elif request_type == "RANDOM": + 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) + 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 = [] + history.append(GPT_SETTINGS[0]) + chat_gpt_config_request_size = num_tokens_from_string(GPT_SETTINGS[0], "gpt-4") + + for slowo, reakcja in WORD_REACTIONS.items(): + if not reakcja[3]: + content = ( + "Kiedy słyszysz " + + slowo + + " to reagujesz lub dzieje się to " + + reakcja[0] + ) + temp = {"role": "system", "content": content} + chat_gpt_config_request_size += num_tokens_from_string(temp, "gpt-4") + history.append(temp) + + final_prompt = username + ":" + prompt + logger.debug( + "Rozmiar zapytania przed dodaniem historii %s", chat_gpt_config_request_size + ) + if request_type == "MUSIC": + algorithm = "gpt-4o" + table = MESSAGE_TABLE_MUZYKA + token_amount = 10700 + elif request_type == "RANDOM": + algorithm = "gpt-4o" + table = MESSAGE_TABLE + token_amount = 10700 + else: + table = MESSAGE_TABLE + algorithm = "gpt-4o" + token_amount = 10700 + + prompt_gpt_request_size = num_tokens_from_string( + {"role": "user", "content": final_prompt}, "gpt-4" + ) + temptable = [] + for i in reversed(table): + temp_token = num_tokens_from_string(i, "gpt-4") + logger.debug( + "Rozmiar zapytania %s prompt %s temp %s", + chat_gpt_config_request_size, + prompt_gpt_request_size, + temp_token, + ) + if ( + chat_gpt_config_request_size + < token_amount + prompt_gpt_request_size + temp_token + ): + temptable.insert(1, i) + chat_gpt_config_request_size += temp_token + history.extend(temptable) + temp = {"role": "user", "content": final_prompt} + history.append(temp) + logger.info("Rozmiar zapytania po wyslaniu %s", chat_gpt_config_request_size) + try: + response = await OPENAICLIENT.chat.completions.create( + model=algorithm, messages=history + ) + except openai.APITimeoutError as e: + # Handle timeout error, e.g. retry or log + result = f"*Kondziu patrzy na terminal, czeka, czeka, czeka,.... Jeszcze chwile czeka Przypierdala w niego pięścią....* Nie mogę się połączyć z Openai spróbuj od nowa. *Na ekranie pojawia się*: {e}" + except openai.APIConnectionError as e: + result = f"*Kondziu patrzy na terminal, chwile się zastanawia. Przypierdala w niego pięścią....* Nie mogę się połączyć z Openai. *Na ekranie pojawia się*: {e}" + except openai.BadRequestError as e: + # Handle invalid request error, e.g. validate parameters or log + resp, _ = await handle_response( + f"Wytlumacz jakie sa zasady dotyczące treści które możesz generować używając Dalle. Wytłumacz błąd {e} prostym językiem. Przeproś za nadmierną cenzurę. Wytłumacz co mogło być nie tak w prompcie 'prompt'", + True, + True, + MESSAGE_TABLE, + username, + "RANDOM", + ) + result = f"Sorki, cenzura: {resp}. Jak chcesz to są kanały na nudle #sexy-foteczky i #kanal-do-fapania *Na ekranie pojawia się: {e}" + except openai.APIResponseValidationError as e: + # Handle invalid request error, e.g. validate parameters or log + resp, _ = await handle_response( + f"Wytlumacz jakie sa zasady dotyczące treści które możesz generować używając Dalle. Wytłumacz błąd {e} prostym językiem. Przeproś za nadmierną cenzurę. Wytłumacz co mogło być nie tak w prompcie 'prompt'", + True, + True, + MESSAGE_TABLE, + username, + "RANDOM", + ) + result = f"Sorki, cenzura: {resp}. Jak chcesz to są kanały na nudle #sexy-foteczky i #kanal-do-fapania *Na ekranie pojawia się: {e}" + except openai.AuthenticationError as e: + # Handle authentication error, e.g. check credentials or log + result = f"*Kondziu patrzy na terminal, chwile się zastanawia. Przypierdala w niego pięścią....* Wołaj szefa - coś się z hasłem zjebało. *Na terminalu pojawia się:* {e}" + except openai.PermissionDeniedError as e: + # Handle permission error, e.g. check scope or log + result = f"*Kondziu patrzy na terminal, chwile się zastanawia. Przypierdala w niego pięścią....* Wołaj szefa - coś się z uprawnieniami zjebało. *Na terminalu pojawia się:* {e}" + except openai.RateLimitError as e: + result = f"*Kondziu patrzy na terminal* Wołaj szefa. Zapłacić rachunki za AI trzeba. Jak chcesz to się na #zebranie dorzuć. {e}" + except openai.UnprocessableEntityError as e: + result = f"*Kondziu patrzy na terminal. Potem na to co każesz mu wysłać....* Ja wiem że jesteśmy w barze BDSM - ale nie da się włożyć TEGO w TO. *Za jego plecami na terminalu pojawia się:* {e}" + except openai.APIError as e: + # Handle API error, e.g. retry or log + result = f"*Kondziu nurkuje za bar, terminal wybucha. Przed tobą ląduje pergamin zapisany pięknym gotykiem a na nim*: {e}" + + logger.info("Historia wysłana:") + logger.info(history) + await asyncio.sleep(15) + result = "" + logger.debug("Odpowiedzi") + logger.info(response) + 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 request_type == "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) + elif request_type == "RANDOM": + 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) + 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) + return result, MESSAGE_TABLE + + +async def get_random_cyclic_message(client): + """ + The function `get_random_cyclic_message` returns a random cyclic message from a list of cyclic + words. + :return: a random cyclic message from the list `cyclic_words`. + """ + logger = logging.getLogger("discord") + channel_id = 1062047367337095268 + channel = client.get_channel(channel_id) + # trunk-ignore(bandit/B311) + ai_check = random.randint(0, 10) + logger.info("Losowa wypowiedź") + if ai_check < 2: + logger.info("Predefiniowana") + # trunk-ignore(bandit/B311) + messnum = random.randint(0, len(CYCLIC_WORDS)) + logger.debug(messnum) + logger.debug(len(CYCLIC_WORDS)) + mess_key = list(CYCLIC_WORDS.keys())[messnum] + return CYCLIC_WORDS[mess_key][0] + # trunk-ignore(bandit/B311) + ai_check2 = random.randint(0, 10) + global MESSAGE_TABLE + if ai_check2 < 6: + logger.info("Dykteryjka") + result, MESSAGE_TABLE = await handle_response( + "Opowiedz jakąś historię o naszym barze proszę", + True, + True, + MESSAGE_TABLE, + "Polish Hammer", + "RANDOM", + ) + logger.info(result) + else: + logger.info("Wtracenie w dyskusje") + messages = [message async for message in channel.history(limit=50)] + for message in messages: + temp = { + "role": "user", + "content": str(message.author) + ":" + str(message.content), + } + MESSAGE_TABLE.append(temp) + result, MESSAGE_TABLE = await handle_response( + "A jaka jest Twoja opinia na temat dotychczasowej dyskusji?", + True, + True, + MESSAGE_TABLE, + "Polish Hammer", + "RANDOM", + ) + logger.info(result) + return result diff --git a/bot.py b/bot.py index 6924761..92afdb4 100644 --- a/bot.py +++ b/bot.py @@ -215,7 +215,6 @@ REMOTE_HOST_NAME = "openai" authTokens = netrc_mod.authenticators(REMOTE_HOST_NAME) openai.api_key = authTokens[2] openAIClient = openai.AsyncOpenAI(api_key=openai.api_key) - REMOTE_HOST_NAME = "spotipy" authTokens = netrc_mod.authenticators(REMOTE_HOST_NAME) spotify_ctrl = spotipy.Spotify( @@ -301,13 +300,14 @@ logger.info("Done") async def on_ready(): """Metoda wywoływana przy połączeniu do serwera.""" logger.debug("%s has connected to Discord!", client.user) - await client.load_extension("voice_recognition") - logger.info("Cogs") + #TODO: load vs reload + #try: + await client.load_extension("voice_recognition_commands") logger.info(client.cogs) await client.change_presence(activity=discord.Game(name="Axe Throwing Darts")) await client.tree.sync() for com in client.commands: - logger.info(com.qualified_name) + logger.info("Command %s is awejleble", com.qualified_name) check_self.start() check_data_q.start() @@ -347,9 +347,13 @@ async def on_message(message): 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) - return + if message.author.id == 346956223645614080: + await message.reply("Witam witam") + return + else: + channel = client.get_channel(1064888712565100614) + await channel.send("Słyszałem ja żem że: " + message.content) + return channel = message.channel await client.process_commands(message) diff --git a/bot_classes.py b/bot_classes.py deleted file mode 100644 index e69de29..0000000 diff --git a/bot_commands.py b/bot_commands.py deleted file mode 100644 index e69de29..0000000 diff --git a/bot_functions.py b/bot_functions.py deleted file mode 100644 index e69de29..0000000 diff --git a/coach.sex.json b/coach.sex.json deleted file mode 100644 index c53bf65..0000000 --- a/coach.sex.json +++ /dev/null @@ -1,1707 +0,0 @@ -{ - "recordsCount": 17, - "records": [ - { - "domainName": "coach.sex", - "domainType": "added", - "createdDateISO8601": null, - "updatedDateISO8601": null, - "expiresDateISO8601": null, - "createdDateRaw": null, - "updatedDateRaw": null, - "expiresDateRaw": null, - "audit": { - "createdDate": "2024-02-12T08:43:20+00:00", - "updatedDate": "2024-02-12T08:43:20+00:00" - }, - "nameServers": [], - "whoisServer": "whois.nic.sex", - "registrarName": null, - "status": [], - "cleanText": "Domain Name: coach.sex\nURL of the ICANN Whois Inaccuracy Complaint Form: https:\/\/www.icann.org\/wicf\/\n>>> This name is not available for registration.\n>>> This name subscribes to the AdultBlock+ product and is not available for registration.\n>>> Last update of WHOIS database: 2024-02-12T08:43:20Z <<<\nFor more information on Whois status codes, please visit https:\/\/icann.org\/epp\nThe Service is provided so that you may look up certain information in relation to domain names that we store in our database.\nUse of the Service is subject to our policies, in particular you should familiarise yourself with our Acceptable Use Policy and our Privacy Policy.\nThe information provided by this Service is 'as is' and we make no guarantee of it its accuracy.\nYou agree that by your use of the Service you will not use the information provided by us in a way which is:\n* inconsistent with any applicable laws,\n* inconsistent with any policy issued by us,\n* to generate, distribute, or facilitate unsolicited mass email, promotions, advertisings or other solicitations, or\n* to enable high volume, automated, electronic processes that apply to the Service.\nYou acknowledge that:\n* a response from the Service that a domain name is 'available', does not guarantee that is able to be registered,\n* we may restrict, suspend or terminate your access to the Service at any time, and\n* the copying, compilation, repackaging, dissemination or other use of the information provided by the Service is not permitted, without our express written consent.\nThis information has been prepared and published in order to represent administrative and technical management of the TLD.\nWe may discontinue or amend any part or the whole of these Terms of Service from time to time at our absolute discretion.\n", - "rawText": "", - "registrantContact": { - "name": null, - "organization": null, - "street": "", - "city": null, - "state": null, - "postalCode": null, - "country": null, - "email": null, - "telephone": null, - "telephoneExt": null, - "fax": null, - "faxExt": null, - "rawText": "" - }, - "administrativeContact": { - "name": null, - "organization": null, - "street": "", - "city": null, - "state": null, - "postalCode": null, - "country": null, - "email": null, - "telephone": null, - "telephoneExt": null, - "fax": null, - "faxExt": null, - "rawText": "" - }, - "technicalContact": { - "name": null, - "organization": null, - "street": "", - "city": null, - "state": null, - "postalCode": null, - "country": null, - "email": null, - "telephone": null, - "telephoneExt": null, - "fax": null, - "faxExt": null, - "rawText": "" - }, - "billingContact": { - "name": null, - "organization": null, - "street": "", - "city": null, - "state": null, - "postalCode": null, - "country": null, - "email": null, - "telephone": null, - "telephoneExt": null, - "fax": null, - "faxExt": null, - "rawText": "" - }, - "zoneContact": { - "name": null, - "organization": null, - "street": "", - "city": null, - "state": null, - "postalCode": null, - "country": null, - "email": null, - "telephone": null, - "telephoneExt": null, - "fax": null, - "faxExt": null, - "rawText": "" - } - }, - { - "domainName": "coach.sex", - "domainType": "added", - "createdDateISO8601": null, - "updatedDateISO8601": null, - "expiresDateISO8601": null, - "createdDateRaw": null, - "updatedDateRaw": null, - "expiresDateRaw": null, - "audit": { - "createdDate": "2021-12-08T07:33:50+00:00", - "updatedDate": "2021-12-08T07:33:50+00:00" - }, - "nameServers": [], - "whoisServer": null, - "registrarName": null, - "status": [], - "cleanText": "Domain Name: coach.sex|URL of the ICANN Whois Inaccuracy Complaint Form: https:\/\/www.icann.org\/wicf\/|>>> This name is not available for registration.|>>> This name subscribes to the AdultBlock+ service.|>>> Last update of WHOIS database: 2021-12-08T07:20:05Z <<<||For more information on Whois status codes, please visit https:\/\/icann.org\/epp||The Service is provided so that you may look up certain information in relation to domain names that we store in our database.||Use of the Service is subject to our policies, in particular you should familiarise yourself with our Acceptable Use Policy and our Privacy Policy.||The information provided by this Service is 'as is' and we make no guarantee of it its accuracy.||You agree that by your use of the Service you will not use the information provided by us in a way which is:|* inconsistent with any applicable laws,|* inconsistent with any policy issued by us,|* to generate, distribute, or facilitate unsolicited mass email, promotions, advertisings or other solicitations, or|* to enable high volume, automated, electronic processes that apply to the Service.||You acknowledge that:|* a response from the Service that a domain name is 'available', does not guarantee that is able to be registered,|* we may restrict, suspend or terminate your access to the Service at any time, and|* the copying, compilation, repackaging, dissemination or other use of the information provided by the Service is not permitted, without our express written consent.||This information has been prepared and published in order to represent administrative and technical management of the TLD.||We may discontinue or amend any part or the whole of these Terms of Service from time to time at our absolute discretion.", - "rawText": "Domain Name: coach.sex|URL of the ICANN Whois Inaccuracy Complaint Form: https:\/\/www.icann.org\/wicf\/|>>> This name is not available for registration.|>>> This name subscribes to the AdultBlock+ service.|>>> Last update of WHOIS database: 2021-12-08T07:20:05Z <<<||For more information on Whois status codes, please visit https:\/\/icann.org\/epp||The Service is provided so that you may look up certain information in relation to domain names that we store in our database.||Use of the Service is subject to our policies, in particular you should familiarise yourself with our Acceptable Use Policy and our Privacy Policy.||The information provided by this Service is 'as is' and we make no guarantee of it its accuracy.||You agree that by your use of the Service you will not use the information provided by us in a way which is:|* inconsistent with any applicable laws,|* inconsistent with any policy issued by us,|* to generate, distribute, or facilitate unsolicited mass email, promotions, advertisings or other solicitations, or|* to enable high volume, automated, electronic processes that apply to the Service.||You acknowledge that:|* a response from the Service that a domain name is 'available', does not guarantee that is able to be registered,|* we may restrict, suspend or terminate your access to the Service at any time, and|* the copying, compilation, repackaging, dissemination or other use of the information provided by the Service is not permitted, without our express written consent.||This information has been prepared and published in order to represent administrative and technical management of the TLD.||We may discontinue or amend any part or the whole of these Terms of Service from time to time at our absolute discretion.", - "registrantContact": { - "name": null, - "organization": null, - "street": "", - "city": null, - "state": null, - "postalCode": null, - "country": null, - "email": null, - "telephone": null, - "telephoneExt": null, - "fax": null, - "faxExt": null, - "rawText": null - }, - "administrativeContact": { - "name": null, - "organization": null, - "street": "", - "city": null, - "state": null, - "postalCode": null, - "country": null, - "email": null, - "telephone": null, - "telephoneExt": null, - "fax": null, - "faxExt": null, - "rawText": null - }, - "technicalContact": { - "name": null, - "organization": null, - "street": "", - "city": null, - "state": null, - "postalCode": null, - "country": null, - "email": null, - "telephone": null, - "telephoneExt": null, - "fax": null, - "faxExt": null, - "rawText": null - }, - "billingContact": { - "name": null, - "organization": null, - "street": "", - "city": null, - "state": null, - "postalCode": null, - "country": null, - "email": null, - "telephone": null, - "telephoneExt": null, - "fax": null, - "faxExt": null, - "rawText": null - }, - "zoneContact": { - "name": null, - "organization": null, - "street": "", - "city": null, - "state": null, - "postalCode": null, - "country": null, - "email": null, - "telephone": null, - "telephoneExt": null, - "fax": null, - "faxExt": null, - "rawText": null - } - }, - { - "domainName": "coach.sex", - "domainType": "added", - "createdDateISO8601": "2018-08-01T20:47:08+00:00", - "updatedDateISO8601": "2021-08-13T19:12:36+00:00", - "expiresDateISO8601": "2021-08-01T20:47:08+00:00", - "createdDateRaw": "2018-08-01T20:47:08Z", - "updatedDateRaw": "2021-08-13T19:12:36Z", - "expiresDateRaw": "2021-08-01T20:47:08Z", - "audit": { - "createdDate": "2021-09-08T05:57:18+00:00", - "updatedDate": "2021-09-08T05:57:18+00:00" - }, - "nameServers": [ - "ns1.zenbox.pl|ns2.zenbox.pl|" - ], - "whoisServer": "whois.instra.com", - "registrarName": "Instra Corporation Pty Ltd", - "status": [ - "clientHold", - "clientTransferProhibited", - "pendingDelete", - "redemptionPeriod" - ], - "cleanText": "Domain Name: coach.sex|Registry Domain ID: D425500000050058539-GDREG|Registrar WHOIS Server: whois.instra.com|Registrar URL: whois.instra.com|Updated Date: 2021-08-13T19:12:36Z|Creation Date: 2018-08-01T20:47:08Z|Registry Expiry Date: 2021-08-01T20:47:08Z|Registrar: Instra Corporation Pty Ltd|Registrar IANA ID: 1376|Registrar Abuse Contact Email:|Registrar Abuse Contact Phone:|Domain Status: clientHold https:\/\/icann.org\/epp#clientHold|Domain Status: clientTransferProhibited https:\/\/icann.org\/epp#clientTransferProhibited|Domain Status: pendingDelete https:\/\/icann.org\/epp#pendingDelete|Domain Status: redemptionPeriod https:\/\/icann.org\/epp#redemptionPeriod|Registry Registrant ID: REDACTED FOR PRIVACY|Registrant Name: REDACTED FOR PRIVACY|Registrant Organization:|Registrant Street: REDACTED FOR PRIVACY|Registrant Street: REDACTED FOR PRIVACY|Registrant Street: REDACTED FOR PRIVACY|Registrant City: REDACTED FOR PRIVACY|Registrant State\/Province: mazowieckie|Registrant Postal Code: REDACTED FOR PRIVACY|Registrant Country: PL|Registrant Phone: REDACTED FOR PRIVACY|Registrant Phone Ext: REDACTED FOR PRIVACY|Registrant Fax: REDACTED FOR PRIVACY|Registrant Fax Ext: REDACTED FOR PRIVACY|Registrant Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.|Registry Admin ID: REDACTED FOR PRIVACY|Admin Name: REDACTED FOR PRIVACY|Admin Organization: REDACTED FOR PRIVACY|Admin Street: REDACTED FOR PRIVACY|Admin Street: REDACTED FOR PRIVACY|Admin Street: REDACTED FOR PRIVACY|Admin City: REDACTED FOR PRIVACY|Admin State\/Province: REDACTED FOR PRIVACY|Admin Postal Code: REDACTED FOR PRIVACY|Admin Country: REDACTED FOR PRIVACY|Admin Phone: REDACTED FOR PRIVACY|Admin Phone Ext: REDACTED FOR PRIVACY|Admin Fax: REDACTED FOR PRIVACY|Admin Fax Ext: REDACTED FOR PRIVACY|Admin Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.|Registry Tech ID: REDACTED FOR PRIVACY|Tech Name: REDACTED FOR PRIVACY|Tech Organization: REDACTED FOR PRIVACY|Tech Street: REDACTED FOR PRIVACY|Tech Street: REDACTED FOR PRIVACY|Tech Street: REDACTED FOR PRIVACY|Tech City: REDACTED FOR PRIVACY|Tech State\/Province: REDACTED FOR PRIVACY|Tech Postal Code: REDACTED FOR PRIVACY|Tech Country: REDACTED FOR PRIVACY|Tech Phone: REDACTED FOR PRIVACY|Tech Phone Ext: REDACTED FOR PRIVACY|Tech Fax: REDACTED FOR PRIVACY|Tech Fax Ext: REDACTED FOR PRIVACY|Tech Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.|Name Server: ns1.zenbox.pl|Name Server: ns2.zenbox.pl|DNSSEC: unsigned|URL of the ICANN Whois Inaccuracy Complaint Form: https:\/\/www.icann.org\/wicf\/|>>> Last update of WHOIS database: 2021-09-08T05:56:45Z <<<||For more information on Whois status codes, please visit https:\/\/icann.org\/epp||The Service is provided so that you may look up certain information in relation to domain names that we store in our database.||Use of the Service is subject to our policies, in particular you should familiarise yourself with our Acceptable Use Policy and our Privacy Policy.||The information provided by this Service is 'as is' and we make no guarantee of it its accuracy.||You agree that by your use of the Service you will not use the information provided by us in a way which is:|* inconsistent with any applicable laws,|* inconsistent with any policy issued by us,|* to generate, distribute, or facilitate unsolicited mass email, promotions, advertisings or other solicitations, or|* to enable high volume, automated, electronic processes that apply to the Service.||You acknowledge that:|* a response from the Service that a domain name is 'available', does not guarantee that is able to be registered,|* we may restrict, suspend or terminate your access to the Service at any time, and|* the copying, compilation, repackaging, dissemination or other use of the information provided by the Service is not permitted, without our express written consent.||This information has been prepared and published in order to represent administrative and technical management of the TLD.||We may discontinue or amend any part or the whole of these Terms of Service from time to time at our absolute discretion.", - "rawText": "Domain Name: coach.sex|Registry Domain ID: D425500000050058539-GDREG|Registrar WHOIS Server: whois.instra.com|Registrar URL: whois.instra.com|Updated Date: 2021-08-13T19:12:36Z|Creation Date: 2018-08-01T20:47:08Z|Registry Expiry Date: 2021-08-01T20:47:08Z|Registrar: Instra Corporation Pty Ltd|Registrar IANA ID: 1376|Registrar Abuse Contact Email:|Registrar Abuse Contact Phone:|Domain Status: clientHold https:\/\/icann.org\/epp#clientHold|Domain Status: clientTransferProhibited https:\/\/icann.org\/epp#clientTransferProhibited|Domain Status: pendingDelete https:\/\/icann.org\/epp#pendingDelete|Domain Status: redemptionPeriod https:\/\/icann.org\/epp#redemptionPeriod|Registry Registrant ID: REDACTED FOR PRIVACY|Registrant Name: REDACTED FOR PRIVACY|Registrant Organization:|Registrant Street: REDACTED FOR PRIVACY|Registrant Street: REDACTED FOR PRIVACY|Registrant Street: REDACTED FOR PRIVACY|Registrant City: REDACTED FOR PRIVACY|Registrant State\/Province: mazowieckie|Registrant Postal Code: REDACTED FOR PRIVACY|Registrant Country: PL|Registrant Phone: REDACTED FOR PRIVACY|Registrant Phone Ext: REDACTED FOR PRIVACY|Registrant Fax: REDACTED FOR PRIVACY|Registrant Fax Ext: REDACTED FOR PRIVACY|Registrant Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.|Registry Admin ID: REDACTED FOR PRIVACY|Admin Name: REDACTED FOR PRIVACY|Admin Organization: REDACTED FOR PRIVACY|Admin Street: REDACTED FOR PRIVACY|Admin Street: REDACTED FOR PRIVACY|Admin Street: REDACTED FOR PRIVACY|Admin City: REDACTED FOR PRIVACY|Admin State\/Province: REDACTED FOR PRIVACY|Admin Postal Code: REDACTED FOR PRIVACY|Admin Country: REDACTED FOR PRIVACY|Admin Phone: REDACTED FOR PRIVACY|Admin Phone Ext: REDACTED FOR PRIVACY|Admin Fax: REDACTED FOR PRIVACY|Admin Fax Ext: REDACTED FOR PRIVACY|Admin Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.|Registry Tech ID: REDACTED FOR PRIVACY|Tech Name: REDACTED FOR PRIVACY|Tech Organization: REDACTED FOR PRIVACY|Tech Street: REDACTED FOR PRIVACY|Tech Street: REDACTED FOR PRIVACY|Tech Street: REDACTED FOR PRIVACY|Tech City: REDACTED FOR PRIVACY|Tech State\/Province: REDACTED FOR PRIVACY|Tech Postal Code: REDACTED FOR PRIVACY|Tech Country: REDACTED FOR PRIVACY|Tech Phone: REDACTED FOR PRIVACY|Tech Phone Ext: REDACTED FOR PRIVACY|Tech Fax: REDACTED FOR PRIVACY|Tech Fax Ext: REDACTED FOR PRIVACY|Tech Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.|Name Server: ns1.zenbox.pl|Name Server: ns2.zenbox.pl|DNSSEC: unsigned|URL of the ICANN Whois Inaccuracy Complaint Form: https:\/\/www.icann.org\/wicf\/|>>> Last update of WHOIS database: 2021-09-08T05:56:45Z <<<||For more information on Whois status codes, please visit https:\/\/icann.org\/epp||The Service is provided so that you may look up certain information in relation to domain names that we store in our database.||Use of the Service is subject to our policies, in particular you should familiarise yourself with our Acceptable Use Policy and our Privacy Policy.||The information provided by this Service is 'as is' and we make no guarantee of it its accuracy.||You agree that by your use of the Service you will not use the information provided by us in a way which is:|* inconsistent with any applicable laws,|* inconsistent with any policy issued by us,|* to generate, distribute, or facilitate unsolicited mass email, promotions, advertisings or other solicitations, or|* to enable high volume, automated, electronic processes that apply to the Service.||You acknowledge that:|* a response from the Service that a domain name is 'available', does not guarantee that is able to be registered,|* we may restrict, suspend or terminate your access to the Service at any time, and|* the copying, compilation, repackaging, dissemination or other use of the information provided by the Service is not permitted, without our express written consent.||This information has been prepared and published in order to represent administrative and technical management of the TLD.||We may discontinue or amend any part or the whole of these Terms of Service from time to time at our absolute discretion.", - "registrantContact": { - "name": "REDACTED FOR PRIVACY", - "organization": null, - "street": "REDACTED FOR PRIVACY", - "city": "REDACTED FOR PRIVACY", - "state": "mazowieckie", - "postalCode": "REDACTED FOR PRIVACY", - "country": "POLAND", - "email": null, - "telephone": null, - "telephoneExt": "REDACTED FOR PRIVACY", - "fax": null, - "faxExt": "REDACTED FOR PRIVACY", - "rawText": "Registrant Name: REDACTED FOR PRIVACY|Registrant Street: REDACTED FOR PRIVACY|Registrant Street: REDACTED FOR PRIVACY|Registrant Street: REDACTED FOR PRIVACY|Registrant City: REDACTED FOR PRIVACY|Registrant State\/Province: mazowieckie|Registrant Postal Code: REDACTED FOR PRIVACY|Registrant Country: PL|Registrant Phone: REDACTED FOR PRIVACY|Registrant Phone Ext: REDACTED FOR PRIVACY|Registrant Fax: REDACTED FOR PRIVACY|Registrant Fax Ext: REDACTED FOR PRIVACY|Registrant Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name." - }, - "administrativeContact": { - "name": "REDACTED FOR PRIVACY", - "organization": "REDACTED FOR PRIVACY", - "street": "REDACTED FOR PRIVACY", - "city": "REDACTED FOR PRIVACY", - "state": "REDACTED FOR PRIVACY", - "postalCode": "REDACTED FOR PRIVACY", - "country": "REDACTED FOR PRIVACY", - "email": null, - "telephone": null, - "telephoneExt": "REDACTED FOR PRIVACY", - "fax": null, - "faxExt": "REDACTED FOR PRIVACY", - "rawText": "Admin Name: REDACTED FOR PRIVACY|Admin Organization: REDACTED FOR PRIVACY|Admin Street: REDACTED FOR PRIVACY|Admin Street: REDACTED FOR PRIVACY|Admin Street: REDACTED FOR PRIVACY|Admin City: REDACTED FOR PRIVACY|Admin State\/Province: REDACTED FOR PRIVACY|Admin Postal Code: REDACTED FOR PRIVACY|Admin Country: REDACTED FOR PRIVACY|Admin Phone: REDACTED FOR PRIVACY|Admin Phone Ext: REDACTED FOR PRIVACY|Admin Fax: REDACTED FOR PRIVACY|Admin Fax Ext: REDACTED FOR PRIVACY|Admin Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name." - }, - "technicalContact": { - "name": "REDACTED FOR PRIVACY", - "organization": "REDACTED FOR PRIVACY", - "street": "REDACTED FOR PRIVACY", - "city": "REDACTED FOR PRIVACY", - "state": "REDACTED FOR PRIVACY", - "postalCode": "REDACTED FOR PRIVACY", - "country": "REDACTED FOR PRIVACY", - "email": null, - "telephone": null, - "telephoneExt": "REDACTED FOR PRIVACY", - "fax": null, - "faxExt": "REDACTED FOR PRIVACY", - "rawText": "Tech Name: REDACTED FOR PRIVACY|Tech Organization: REDACTED FOR PRIVACY|Tech Street: REDACTED FOR PRIVACY|Tech Street: REDACTED FOR PRIVACY|Tech Street: REDACTED FOR PRIVACY|Tech City: REDACTED FOR PRIVACY|Tech State\/Province: REDACTED FOR PRIVACY|Tech Postal Code: REDACTED FOR PRIVACY|Tech Country: REDACTED FOR PRIVACY|Tech Phone: REDACTED FOR PRIVACY|Tech Phone Ext: REDACTED FOR PRIVACY|Tech Fax: REDACTED FOR PRIVACY|Tech Fax Ext: REDACTED FOR PRIVACY|Tech Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name." - }, - "billingContact": { - "name": null, - "organization": null, - "street": "", - "city": null, - "state": null, - "postalCode": null, - "country": null, - "email": null, - "telephone": null, - "telephoneExt": null, - "fax": null, - "faxExt": null, - "rawText": null - }, - "zoneContact": { - "name": null, - "organization": null, - "street": "", - "city": null, - "state": null, - "postalCode": null, - "country": null, - "email": null, - "telephone": null, - "telephoneExt": null, - "fax": null, - "faxExt": null, - "rawText": null - } - }, - { - "domainName": "coach.sex", - "domainType": "added", - "createdDateISO8601": "2018-08-01T20:47:08+00:00", - "updatedDateISO8601": "2021-08-13T19:12:36+00:00", - "expiresDateISO8601": "2021-08-01T20:47:08+00:00", - "createdDateRaw": "2018-08-01T20:47:08Z", - "updatedDateRaw": "2021-08-13T19:12:36Z", - "expiresDateRaw": "2021-08-01T20:47:08Z", - "audit": { - "createdDate": "2021-08-22T15:19:04+00:00", - "updatedDate": "2021-08-22T15:19:04+00:00" - }, - "nameServers": [ - "ns1.zenbox.pl|ns2.zenbox.pl|" - ], - "whoisServer": "whois.instra.com", - "registrarName": "Instra Corporation Pty Ltd", - "status": [ - "clientHold", - "clientTransferProhibited", - "autoRenewPeriod" - ], - "cleanText": "Domain Name: coach.sex|Registry Domain ID: D425500000050058539-GDREG|Registrar WHOIS Server: whois.instra.com|Registrar URL: whois.instra.com|Updated Date: 2021-08-13T19:12:36Z|Creation Date: 2018-08-01T20:47:08Z|Registry Expiry Date: 2021-08-01T20:47:08Z|Registrar: Instra Corporation Pty Ltd|Registrar IANA ID: 1376|Registrar Abuse Contact Email:|Registrar Abuse Contact Phone:|Domain Status: clientHold https:\/\/icann.org\/epp#clientHold|Domain Status: clientTransferProhibited https:\/\/icann.org\/epp#clientTransferProhibited|Domain Status: autoRenewPeriod https:\/\/icann.org\/epp#autoRenewPeriod|Registry Registrant ID: REDACTED FOR PRIVACY|Registrant Name: REDACTED FOR PRIVACY|Registrant Organization:|Registrant Street: REDACTED FOR PRIVACY|Registrant Street: REDACTED FOR PRIVACY|Registrant Street: REDACTED FOR PRIVACY|Registrant City: REDACTED FOR PRIVACY|Registrant State\/Province: mazowieckie|Registrant Postal Code: REDACTED FOR PRIVACY|Registrant Country: PL|Registrant Phone: REDACTED FOR PRIVACY|Registrant Phone Ext: REDACTED FOR PRIVACY|Registrant Fax: REDACTED FOR PRIVACY|Registrant Fax Ext: REDACTED FOR PRIVACY|Registrant Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.|Registry Admin ID: REDACTED FOR PRIVACY|Admin Name: REDACTED FOR PRIVACY|Admin Organization: REDACTED FOR PRIVACY|Admin Street: REDACTED FOR PRIVACY|Admin Street: REDACTED FOR PRIVACY|Admin Street: REDACTED FOR PRIVACY|Admin City: REDACTED FOR PRIVACY|Admin State\/Province: REDACTED FOR PRIVACY|Admin Postal Code: REDACTED FOR PRIVACY|Admin Country: REDACTED FOR PRIVACY|Admin Phone: REDACTED FOR PRIVACY|Admin Phone Ext: REDACTED FOR PRIVACY|Admin Fax: REDACTED FOR PRIVACY|Admin Fax Ext: REDACTED FOR PRIVACY|Admin Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.|Registry Tech ID: REDACTED FOR PRIVACY|Tech Name: REDACTED FOR PRIVACY|Tech Organization: REDACTED FOR PRIVACY|Tech Street: REDACTED FOR PRIVACY|Tech Street: REDACTED FOR PRIVACY|Tech Street: REDACTED FOR PRIVACY|Tech City: REDACTED FOR PRIVACY|Tech State\/Province: REDACTED FOR PRIVACY|Tech Postal Code: REDACTED FOR PRIVACY|Tech Country: REDACTED FOR PRIVACY|Tech Phone: REDACTED FOR PRIVACY|Tech Phone Ext: REDACTED FOR PRIVACY|Tech Fax: REDACTED FOR PRIVACY|Tech Fax Ext: REDACTED FOR PRIVACY|Tech Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.|Name Server: ns1.zenbox.pl|Name Server: ns2.zenbox.pl|DNSSEC: unsigned|URL of the ICANN Whois Inaccuracy Complaint Form: https:\/\/www.icann.org\/wicf\/|>>> Last update of WHOIS database: 2021-08-22T14:58:12Z <<<||For more information on Whois status codes, please visit https:\/\/icann.org\/epp||The Service is provided so that you may look up certain information in relation to domain names that we store in our database.||Use of the Service is subject to our policies, in particular you should familiarise yourself with our Acceptable Use Policy and our Privacy Policy.||The information provided by this Service is 'as is' and we make no guarantee of it its accuracy.||You agree that by your use of the Service you will not use the information provided by us in a way which is:|* inconsistent with any applicable laws,|* inconsistent with any policy issued by us,|* to generate, distribute, or facilitate unsolicited mass email, promotions, advertisings or other solicitations, or|* to enable high volume, automated, electronic processes that apply to the Service.||You acknowledge that:|* a response from the Service that a domain name is 'available', does not guarantee that is able to be registered,|* we may restrict, suspend or terminate your access to the Service at any time, and|* the copying, compilation, repackaging, dissemination or other use of the information provided by the Service is not permitted, without our express written consent.||This information has been prepared and published in order to represent administrative and technical management of the TLD.||We may discontinue or amend any part or the whole of these Terms of Service from time to time at our absolute discretion.", - "rawText": "", - "registrantContact": { - "name": "REDACTED FOR PRIVACY", - "organization": "", - "street": "REDACTED FOR PRIVACY", - "city": "REDACTED FOR PRIVACY", - "state": "mazowieckie", - "postalCode": "REDACTED FOR PRIVACY", - "country": "POLAND", - "email": "", - "telephone": "", - "telephoneExt": "REDACTED FOR PRIVACY", - "fax": "", - "faxExt": "REDACTED FOR PRIVACY", - "rawText": "Registrant Name: REDACTED FOR PRIVACY|Registrant Street: REDACTED FOR PRIVACY|Registrant Street: REDACTED FOR PRIVACY|Registrant Street: REDACTED FOR PRIVACY|Registrant City: REDACTED FOR PRIVACY|Registrant State\/Province: mazowieckie|Registrant Postal Code: REDACTED FOR PRIVACY|Registrant Country: PL|Registrant Phone: REDACTED FOR PRIVACY|Registrant Phone Ext: REDACTED FOR PRIVACY|Registrant Fax: REDACTED FOR PRIVACY|Registrant Fax Ext: REDACTED FOR PRIVACY|Registrant Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name." - }, - "administrativeContact": { - "name": "REDACTED FOR PRIVACY", - "organization": "REDACTED FOR PRIVACY", - "street": "REDACTED FOR PRIVACY", - "city": "REDACTED FOR PRIVACY", - "state": "REDACTED FOR PRIVACY", - "postalCode": "REDACTED FOR PRIVACY", - "country": "REDACTED FOR PRIVACY", - "email": "", - "telephone": "", - "telephoneExt": "REDACTED FOR PRIVACY", - "fax": "", - "faxExt": "REDACTED FOR PRIVACY", - "rawText": "Admin Name: REDACTED FOR PRIVACY|Admin Organization: REDACTED FOR PRIVACY|Admin Street: REDACTED FOR PRIVACY|Admin Street: REDACTED FOR PRIVACY|Admin Street: REDACTED FOR PRIVACY|Admin City: REDACTED FOR PRIVACY|Admin State\/Province: REDACTED FOR PRIVACY|Admin Postal Code: REDACTED FOR PRIVACY|Admin Country: REDACTED FOR PRIVACY|Admin Phone: REDACTED FOR PRIVACY|Admin Phone Ext: REDACTED FOR PRIVACY|Admin Fax: REDACTED FOR PRIVACY|Admin Fax Ext: REDACTED FOR PRIVACY|Admin Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name." - }, - "technicalContact": { - "name": "REDACTED FOR PRIVACY", - "organization": "REDACTED FOR PRIVACY", - "street": "REDACTED FOR PRIVACY", - "city": "REDACTED FOR PRIVACY", - "state": "REDACTED FOR PRIVACY", - "postalCode": "REDACTED FOR PRIVACY", - "country": "REDACTED FOR PRIVACY", - "email": "", - "telephone": "", - "telephoneExt": "REDACTED FOR PRIVACY", - "fax": "", - "faxExt": "REDACTED FOR PRIVACY", - "rawText": "Tech Name: REDACTED FOR PRIVACY|Tech Organization: REDACTED FOR PRIVACY|Tech Street: REDACTED FOR PRIVACY|Tech Street: REDACTED FOR PRIVACY|Tech Street: REDACTED FOR PRIVACY|Tech City: REDACTED FOR PRIVACY|Tech State\/Province: REDACTED FOR PRIVACY|Tech Postal Code: REDACTED FOR PRIVACY|Tech Country: REDACTED FOR PRIVACY|Tech Phone: REDACTED FOR PRIVACY|Tech Phone Ext: REDACTED FOR PRIVACY|Tech Fax: REDACTED FOR PRIVACY|Tech Fax Ext: REDACTED FOR PRIVACY|Tech Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name." - }, - "billingContact": { - "name": "", - "organization": "", - "street": "", - "city": "", - "state": "", - "postalCode": "", - "country": "", - "email": "", - "telephone": "", - "telephoneExt": "", - "fax": "", - "faxExt": "", - "rawText": "" - }, - "zoneContact": { - "name": "", - "organization": "", - "street": "", - "city": "", - "state": "", - "postalCode": "", - "country": "", - "email": "", - "telephone": "", - "telephoneExt": "", - "fax": "", - "faxExt": "", - "rawText": "" - } - }, - { - "domainName": "coach.sex", - "domainType": "dropped", - "createdDateISO8601": "2018-08-01T20:47:08+00:00", - "updatedDateISO8601": "2021-08-13T19:12:36+00:00", - "expiresDateISO8601": "2021-08-01T20:47:08+00:00", - "createdDateRaw": "2018-08-01T20:47:08Z", - "updatedDateRaw": "2021-08-13T19:12:36Z", - "expiresDateRaw": "2021-08-01T20:47:08Z", - "audit": { - "createdDate": "2021-08-14T17:12:55+00:00", - "updatedDate": "2021-08-14T17:12:55+00:00" - }, - "nameServers": [ - "ns1.zenbox.pl", - "ns2.zenbox.pl" - ], - "whoisServer": "whois.instra.com", - "registrarName": "Instra Corporation Pty Ltd", - "status": [ - "clientHold", - "clientTransferProhibited", - "autoRenewPeriod" - ], - "cleanText": "Domain Name: coach.sex\nRegistrar WHOIS Server: whois.instra.com\nRegistrar URL: whois.instra.com\nUpdated Date: 2021-08-13T19:12:36Z\nCreation Date: 2018-08-01T20:47:08Z\nRegistry Expiry Date: 2021-08-01T20:47:08Z\nRegistrar: Instra Corporation Pty Ltd\nRegistrar IANA ID: 1376\nDomain Status: clientHold https:\/\/icann.org\/epp#clientHold\nDomain Status: clientTransferProhibited https:\/\/icann.org\/epp#clientTransferProhibited\nDomain Status: autoRenewPeriod https:\/\/icann.org\/epp#autoRenewPeriod\nRegistrant Name: REDACTED FOR PRIVACY\nRegistrant Street: REDACTED FOR PRIVACY\nRegistrant Street: REDACTED FOR PRIVACY\nRegistrant Street: REDACTED FOR PRIVACY\nRegistrant City: REDACTED FOR PRIVACY\nRegistrant State\/Province: mazowieckie\nRegistrant Postal Code: REDACTED FOR PRIVACY\nRegistrant Country: PL\nRegistrant Phone: REDACTED FOR PRIVACY\nRegistrant Fax: REDACTED FOR PRIVACY\nRegistrant Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.\nAdmin Name: REDACTED FOR PRIVACY\nAdmin Organization: REDACTED FOR PRIVACY\nAdmin Street: REDACTED FOR PRIVACY\nAdmin Street: REDACTED FOR PRIVACY\nAdmin Street: REDACTED FOR PRIVACY\nAdmin City: REDACTED FOR PRIVACY\nAdmin State\/Province: REDACTED FOR PRIVACY\nAdmin Postal Code: REDACTED FOR PRIVACY\nAdmin Country: REDACTED FOR PRIVACY\nAdmin Phone: REDACTED FOR PRIVACY\nAdmin Fax: REDACTED FOR PRIVACY\nAdmin Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.\nTech Name: REDACTED FOR PRIVACY\nTech Organization: REDACTED FOR PRIVACY\nTech Street: REDACTED FOR PRIVACY\nTech Street: REDACTED FOR PRIVACY\nTech Street: REDACTED FOR PRIVACY\nTech City: REDACTED FOR PRIVACY\nTech State\/Province: REDACTED FOR PRIVACY\nTech Postal Code: REDACTED FOR PRIVACY\nTech Country: REDACTED FOR PRIVACY\nTech Phone: REDACTED FOR PRIVACY\nTech Fax: REDACTED FOR PRIVACY\nTech Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.\nName Server: ns1.zenbox.pl\nName Server: ns2.zenbox.pl\n", - "rawText": "Domain Name: coach.sex\nRegistry Domain ID: D425500000050058539-GDREG\nRegistrar WHOIS Server: whois.instra.com\nRegistrar URL: whois.instra.com\nUpdated Date: 2021-08-13T19:12:36Z\nCreation Date: 2018-08-01T20:47:08Z\nRegistry Expiry Date: 2021-08-01T20:47:08Z\nRegistrar: Instra Corporation Pty Ltd\nRegistrar IANA ID: 1376\nRegistrar Abuse Contact Email:\nRegistrar Abuse Contact Phone:\nDomain Status: clientHold https:\/\/icann.org\/epp#clientHold\nDomain Status: clientTransferProhibited https:\/\/icann.org\/epp#clientTransferProhibited\nDomain Status: autoRenewPeriod https:\/\/icann.org\/epp#autoRenewPeriod\nRegistry Registrant ID: REDACTED FOR PRIVACY\nRegistrant Name: REDACTED FOR PRIVACY\nRegistrant Organization:\nRegistrant Street: REDACTED FOR PRIVACY\nRegistrant Street: REDACTED FOR PRIVACY\nRegistrant Street: REDACTED FOR PRIVACY\nRegistrant City: REDACTED FOR PRIVACY\nRegistrant State\/Province: mazowieckie\nRegistrant Postal Code: REDACTED FOR PRIVACY\nRegistrant Country: PL\nRegistrant Phone: REDACTED FOR PRIVACY\nRegistrant Phone Ext: REDACTED FOR PRIVACY\nRegistrant Fax: REDACTED FOR PRIVACY\nRegistrant Fax Ext: REDACTED FOR PRIVACY\nRegistrant Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.\nRegistry Admin ID: REDACTED FOR PRIVACY\nAdmin Name: REDACTED FOR PRIVACY\nAdmin Organization: REDACTED FOR PRIVACY\nAdmin Street: REDACTED FOR PRIVACY\nAdmin Street: REDACTED FOR PRIVACY\nAdmin Street: REDACTED FOR PRIVACY\nAdmin City: REDACTED FOR PRIVACY\nAdmin State\/Province: REDACTED FOR PRIVACY\nAdmin Postal Code: REDACTED FOR PRIVACY\nAdmin Country: REDACTED FOR PRIVACY\nAdmin Phone: REDACTED FOR PRIVACY\nAdmin Phone Ext: REDACTED FOR PRIVACY\nAdmin Fax: REDACTED FOR PRIVACY\nAdmin Fax Ext: REDACTED FOR PRIVACY\nAdmin Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.\nRegistry Tech ID: REDACTED FOR PRIVACY\nTech Name: REDACTED FOR PRIVACY\nTech Organization: REDACTED FOR PRIVACY\nTech Street: REDACTED FOR PRIVACY\nTech Street: REDACTED FOR PRIVACY\nTech Street: REDACTED FOR PRIVACY\nTech City: REDACTED FOR PRIVACY\nTech State\/Province: REDACTED FOR PRIVACY\nTech Postal Code: REDACTED FOR PRIVACY\nTech Country: REDACTED FOR PRIVACY\nTech Phone: REDACTED FOR PRIVACY\nTech Phone Ext: REDACTED FOR PRIVACY\nTech Fax: REDACTED FOR PRIVACY\nTech Fax Ext: REDACTED FOR PRIVACY\nTech Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.\nName Server: ns1.zenbox.pl\nName Server: ns2.zenbox.pl\nDNSSEC: unsigned\nURL of the ICANN Whois Inaccuracy Complaint Form: https:\/\/www.icann.org\/wicf\/\n>>> Last update of WHOIS database: 2021-08-14T17:12:44Z <<<\n\nFor more information on Whois status codes, please visit https:\/\/icann.org\/epp\n\nThe Service is provided so that you may look up certain information in relation to domain names that we store in our database.\n\nUse of the Service is subject to our policies, in particular you should familiarise yourself with our Acceptable Use Policy and our Privacy Policy.\n\nThe information provided by this Service is 'as is' and we make no guarantee of it its accuracy.\n\nYou agree that by your use of the Service you will not use the information provided by us in a way which is:\n* inconsistent with any applicable laws,\n* inconsistent with any policy issued by us,\n* to generate, distribute, or facilitate unsolicited mass email, promotions, advertisings or other solicitations, or\n* to enable high volume, automated, electronic processes that apply to the Service.\n\nYou acknowledge that:\n* a response from the Service that a domain name is 'available', does not guarantee that is able to be registered,\n* we may restrict, suspend or terminate your access to the Service at any time, and\n* the copying, compilation, repackaging, dissemination or other use of the information provided by the Service is not permitted, without our express written consent.\n\nThis information has been prepared and published in order to represent administrative and technical management of the TLD.\n\nWe may discontinue or amend any part or the whole of these Terms of Service from time to time at our absolute discretion.", - "registrantContact": { - "name": "REDACTED FOR PRIVACY", - "organization": null, - "street": "REDACTED FOR PRIVACY", - "city": "REDACTED FOR PRIVACY", - "state": "mazowieckie", - "postalCode": "REDACTED FOR PRIVACY", - "country": "POLAND", - "email": null, - "telephone": "", - "telephoneExt": null, - "fax": "", - "faxExt": null, - "rawText": "Registrant Name: REDACTED FOR PRIVACY\nRegistrant Street: REDACTED FOR PRIVACY\nRegistrant Street: REDACTED FOR PRIVACY\nRegistrant Street: REDACTED FOR PRIVACY\nRegistrant City: REDACTED FOR PRIVACY\nRegistrant State\/Province: mazowieckie\nRegistrant Postal Code: REDACTED FOR PRIVACY\nRegistrant Country: PL\nRegistrant Phone: REDACTED FOR PRIVACY\nRegistrant Fax: REDACTED FOR PRIVACY\nRegistrant Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name." - }, - "administrativeContact": { - "name": "REDACTED FOR PRIVACY", - "organization": "REDACTED FOR PRIVACY", - "street": "REDACTED FOR PRIVACY", - "city": "REDACTED FOR PRIVACY", - "state": "REDACTED FOR PRIVACY", - "postalCode": "REDACTED FOR PRIVACY", - "country": "REDACTED FOR PRIVACY", - "email": null, - "telephone": "", - "telephoneExt": null, - "fax": "", - "faxExt": null, - "rawText": "Admin Name: REDACTED FOR PRIVACY\nAdmin Organization: REDACTED FOR PRIVACY\nAdmin Street: REDACTED FOR PRIVACY\nAdmin Street: REDACTED FOR PRIVACY\nAdmin Street: REDACTED FOR PRIVACY\nAdmin City: REDACTED FOR PRIVACY\nAdmin State\/Province: REDACTED FOR PRIVACY\nAdmin Postal Code: REDACTED FOR PRIVACY\nAdmin Country: REDACTED FOR PRIVACY\nAdmin Phone: REDACTED FOR PRIVACY\nAdmin Fax: REDACTED FOR PRIVACY\nAdmin Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name." - }, - "technicalContact": { - "name": "REDACTED FOR PRIVACY", - "organization": "REDACTED FOR PRIVACY", - "street": "REDACTED FOR PRIVACY", - "city": "REDACTED FOR PRIVACY", - "state": "REDACTED FOR PRIVACY", - "postalCode": "REDACTED FOR PRIVACY", - "country": "REDACTED FOR PRIVACY", - "email": null, - "telephone": "", - "telephoneExt": null, - "fax": "", - "faxExt": null, - "rawText": "Tech Name: REDACTED FOR PRIVACY\nTech Organization: REDACTED FOR PRIVACY\nTech Street: REDACTED FOR PRIVACY\nTech Street: REDACTED FOR PRIVACY\nTech Street: REDACTED FOR PRIVACY\nTech City: REDACTED FOR PRIVACY\nTech State\/Province: REDACTED FOR PRIVACY\nTech Postal Code: REDACTED FOR PRIVACY\nTech Country: REDACTED FOR PRIVACY\nTech Phone: REDACTED FOR PRIVACY\nTech Fax: REDACTED FOR PRIVACY\nTech Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name." - }, - "billingContact": { - "name": null, - "organization": null, - "street": "", - "city": null, - "state": null, - "postalCode": null, - "country": null, - "email": null, - "telephone": null, - "telephoneExt": null, - "fax": null, - "faxExt": null, - "rawText": null - }, - "zoneContact": { - "name": null, - "organization": null, - "street": "", - "city": null, - "state": null, - "postalCode": null, - "country": null, - "email": null, - "telephone": null, - "telephoneExt": null, - "fax": null, - "faxExt": null, - "rawText": null - } - }, - { - "domainName": "coach.sex", - "domainType": "added", - "createdDateISO8601": "2018-08-01T20:47:08+00:00", - "updatedDateISO8601": "2020-09-15T20:48:28+00:00", - "expiresDateISO8601": "2021-08-01T20:47:08+00:00", - "createdDateRaw": "2018-08-01T20:47:08Z", - "updatedDateRaw": "2020-09-15T20:48:28Z", - "expiresDateRaw": "2021-08-01T20:47:08Z", - "audit": { - "createdDate": "2021-06-17T12:11:23+00:00", - "updatedDate": "2021-06-17T12:11:23+00:00" - }, - "nameServers": [ - "ns2.zenbox.pl|ns1.zenbox.pl|" - ], - "whoisServer": "whois.instra.com", - "registrarName": "Instra Corporation Pty Ltd", - "status": [ - "clientTransferProhibited" - ], - "cleanText": "Domain Name: coach.sex|Registry Domain ID: D425500000050058539-GDREG|Registrar WHOIS Server: whois.instra.com|Registrar URL: whois.instra.com|Updated Date: 2020-09-15T20:48:28Z|Creation Date: 2018-08-01T20:47:08Z|Registry Expiry Date: 2021-08-01T20:47:08Z|Registrar: Instra Corporation Pty Ltd|Registrar IANA ID: 1376|Registrar Abuse Contact Email:|Registrar Abuse Contact Phone:|Domain Status: clientTransferProhibited https:\/\/icann.org\/epp#clientTransferProhibited|Registry Registrant ID: REDACTED FOR PRIVACY|Registrant Name: REDACTED FOR PRIVACY|Registrant Organization:|Registrant Street: REDACTED FOR PRIVACY|Registrant Street: REDACTED FOR PRIVACY|Registrant Street: REDACTED FOR PRIVACY|Registrant City: REDACTED FOR PRIVACY|Registrant State\/Province: mazowieckie|Registrant Postal Code: REDACTED FOR PRIVACY|Registrant Country: PL|Registrant Phone: REDACTED FOR PRIVACY|Registrant Phone Ext: REDACTED FOR PRIVACY|Registrant Fax: REDACTED FOR PRIVACY|Registrant Fax Ext: REDACTED FOR PRIVACY|Registrant Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.|Registry Admin ID: REDACTED FOR PRIVACY|Admin Name: REDACTED FOR PRIVACY|Admin Organization: REDACTED FOR PRIVACY|Admin Street: REDACTED FOR PRIVACY|Admin Street: REDACTED FOR PRIVACY|Admin Street: REDACTED FOR PRIVACY|Admin City: REDACTED FOR PRIVACY|Admin State\/Province: REDACTED FOR PRIVACY|Admin Postal Code: REDACTED FOR PRIVACY|Admin Country: REDACTED FOR PRIVACY|Admin Phone: REDACTED FOR PRIVACY|Admin Phone Ext: REDACTED FOR PRIVACY|Admin Fax: REDACTED FOR PRIVACY|Admin Fax Ext: REDACTED FOR PRIVACY|Admin Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.|Registry Tech ID: REDACTED FOR PRIVACY|Tech Name: REDACTED FOR PRIVACY|Tech Organization: REDACTED FOR PRIVACY|Tech Street: REDACTED FOR PRIVACY|Tech Street: REDACTED FOR PRIVACY|Tech Street: REDACTED FOR PRIVACY|Tech City: REDACTED FOR PRIVACY|Tech State\/Province: REDACTED FOR PRIVACY|Tech Postal Code: REDACTED FOR PRIVACY|Tech Country: REDACTED FOR PRIVACY|Tech Phone: REDACTED FOR PRIVACY|Tech Phone Ext: REDACTED FOR PRIVACY|Tech Fax: REDACTED FOR PRIVACY|Tech Fax Ext: REDACTED FOR PRIVACY|Tech Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.|Name Server: ns2.zenbox.pl|Name Server: ns1.zenbox.pl|DNSSEC: unsigned|URL of the ICANN Whois Inaccuracy Complaint Form: https:\/\/www.icann.org\/wicf\/|>>> Last update of WHOIS database: 2021-06-17T11:55:38Z <<<||For more information on Whois status codes, please visit https:\/\/icann.org\/epp||The Service is provided so that you may look up certain information in relation to domain names that we store in our database.||Use of the Service is subject to our policies, in particular you should familiarise yourself with our Acceptable Use Policy and our Privacy Policy.||The information provided by this Service is 'as is' and we make no guarantee of it its accuracy.||You agree that by your use of the Service you will not use the information provided by us in a way which is:|* inconsistent with any applicable laws,|* inconsistent with any policy issued by us,|* to generate, distribute, or facilitate unsolicited mass email, promotions, advertisings or other solicitations, or|* to enable high volume, automated, electronic processes that apply to the Service.||You acknowledge that:|* a response from the Service that a domain name is 'available', does not guarantee that is able to be registered,|* we may restrict, suspend or terminate your access to the Service at any time, and|* the copying, compilation, repackaging, dissemination or other use of the information provided by the Service is not permitted, without our express written consent.||This information has been prepared and published in order to represent administrative and technical management of the TLD.||We may discontinue or amend any part or the whole of these Terms of Service from time to time at our absolute discretion.", - "rawText": "Domain Name: coach.sex|Registry Domain ID: D425500000050058539-GDREG|Registrar WHOIS Server: whois.instra.com|Registrar URL: whois.instra.com|Updated Date: 2020-09-15T20:48:28Z|Creation Date: 2018-08-01T20:47:08Z|Registry Expiry Date: 2021-08-01T20:47:08Z|Registrar: Instra Corporation Pty Ltd|Registrar IANA ID: 1376|Registrar Abuse Contact Email:|Registrar Abuse Contact Phone:|Domain Status: clientTransferProhibited https:\/\/icann.org\/epp#clientTransferProhibited|Registry Registrant ID: REDACTED FOR PRIVACY|Registrant Name: REDACTED FOR PRIVACY|Registrant Organization:|Registrant Street: REDACTED FOR PRIVACY|Registrant Street: REDACTED FOR PRIVACY|Registrant Street: REDACTED FOR PRIVACY|Registrant City: REDACTED FOR PRIVACY|Registrant State\/Province: mazowieckie|Registrant Postal Code: REDACTED FOR PRIVACY|Registrant Country: PL|Registrant Phone: REDACTED FOR PRIVACY|Registrant Phone Ext: REDACTED FOR PRIVACY|Registrant Fax: REDACTED FOR PRIVACY|Registrant Fax Ext: REDACTED FOR PRIVACY|Registrant Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.|Registry Admin ID: REDACTED FOR PRIVACY|Admin Name: REDACTED FOR PRIVACY|Admin Organization: REDACTED FOR PRIVACY|Admin Street: REDACTED FOR PRIVACY|Admin Street: REDACTED FOR PRIVACY|Admin Street: REDACTED FOR PRIVACY|Admin City: REDACTED FOR PRIVACY|Admin State\/Province: REDACTED FOR PRIVACY|Admin Postal Code: REDACTED FOR PRIVACY|Admin Country: REDACTED FOR PRIVACY|Admin Phone: REDACTED FOR PRIVACY|Admin Phone Ext: REDACTED FOR PRIVACY|Admin Fax: REDACTED FOR PRIVACY|Admin Fax Ext: REDACTED FOR PRIVACY|Admin Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.|Registry Tech ID: REDACTED FOR PRIVACY|Tech Name: REDACTED FOR PRIVACY|Tech Organization: REDACTED FOR PRIVACY|Tech Street: REDACTED FOR PRIVACY|Tech Street: REDACTED FOR PRIVACY|Tech Street: REDACTED FOR PRIVACY|Tech City: REDACTED FOR PRIVACY|Tech State\/Province: REDACTED FOR PRIVACY|Tech Postal Code: REDACTED FOR PRIVACY|Tech Country: REDACTED FOR PRIVACY|Tech Phone: REDACTED FOR PRIVACY|Tech Phone Ext: REDACTED FOR PRIVACY|Tech Fax: REDACTED FOR PRIVACY|Tech Fax Ext: REDACTED FOR PRIVACY|Tech Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.|Name Server: ns2.zenbox.pl|Name Server: ns1.zenbox.pl|DNSSEC: unsigned|URL of the ICANN Whois Inaccuracy Complaint Form: https:\/\/www.icann.org\/wicf\/|>>> Last update of WHOIS database: 2021-06-17T11:55:38Z <<<||For more information on Whois status codes, please visit https:\/\/icann.org\/epp||The Service is provided so that you may look up certain information in relation to domain names that we store in our database.||Use of the Service is subject to our policies, in particular you should familiarise yourself with our Acceptable Use Policy and our Privacy Policy.||The information provided by this Service is 'as is' and we make no guarantee of it its accuracy.||You agree that by your use of the Service you will not use the information provided by us in a way which is:|* inconsistent with any applicable laws,|* inconsistent with any policy issued by us,|* to generate, distribute, or facilitate unsolicited mass email, promotions, advertisings or other solicitations, or|* to enable high volume, automated, electronic processes that apply to the Service.||You acknowledge that:|* a response from the Service that a domain name is 'available', does not guarantee that is able to be registered,|* we may restrict, suspend or terminate your access to the Service at any time, and|* the copying, compilation, repackaging, dissemination or other use of the information provided by the Service is not permitted, without our express written consent.||This information has been prepared and published in order to represent administrative and technical management of the TLD.||We may discontinue or amend any part or the whole of these Terms of Service from time to time at our absolute discretion.", - "registrantContact": { - "name": "REDACTED FOR PRIVACY", - "organization": null, - "street": "REDACTED FOR PRIVACY", - "city": "REDACTED FOR PRIVACY", - "state": "mazowieckie", - "postalCode": "REDACTED FOR PRIVACY", - "country": "POLAND", - "email": null, - "telephone": null, - "telephoneExt": "REDACTED FOR PRIVACY", - "fax": null, - "faxExt": "REDACTED FOR PRIVACY", - "rawText": "Registrant Name: REDACTED FOR PRIVACY|Registrant Street: REDACTED FOR PRIVACY|Registrant Street: REDACTED FOR PRIVACY|Registrant Street: REDACTED FOR PRIVACY|Registrant City: REDACTED FOR PRIVACY|Registrant State\/Province: mazowieckie|Registrant Postal Code: REDACTED FOR PRIVACY|Registrant Country: PL|Registrant Phone: REDACTED FOR PRIVACY|Registrant Phone Ext: REDACTED FOR PRIVACY|Registrant Fax: REDACTED FOR PRIVACY|Registrant Fax Ext: REDACTED FOR PRIVACY|Registrant Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name." - }, - "administrativeContact": { - "name": "REDACTED FOR PRIVACY", - "organization": "REDACTED FOR PRIVACY", - "street": "REDACTED FOR PRIVACY", - "city": "REDACTED FOR PRIVACY", - "state": "REDACTED FOR PRIVACY", - "postalCode": "REDACTED FOR PRIVACY", - "country": "REDACTED FOR PRIVACY", - "email": null, - "telephone": null, - "telephoneExt": "REDACTED FOR PRIVACY", - "fax": null, - "faxExt": "REDACTED FOR PRIVACY", - "rawText": "Admin Name: REDACTED FOR PRIVACY|Admin Organization: REDACTED FOR PRIVACY|Admin Street: REDACTED FOR PRIVACY|Admin Street: REDACTED FOR PRIVACY|Admin Street: REDACTED FOR PRIVACY|Admin City: REDACTED FOR PRIVACY|Admin State\/Province: REDACTED FOR PRIVACY|Admin Postal Code: REDACTED FOR PRIVACY|Admin Country: REDACTED FOR PRIVACY|Admin Phone: REDACTED FOR PRIVACY|Admin Phone Ext: REDACTED FOR PRIVACY|Admin Fax: REDACTED FOR PRIVACY|Admin Fax Ext: REDACTED FOR PRIVACY|Admin Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name." - }, - "technicalContact": { - "name": "REDACTED FOR PRIVACY", - "organization": "REDACTED FOR PRIVACY", - "street": "REDACTED FOR PRIVACY", - "city": "REDACTED FOR PRIVACY", - "state": "REDACTED FOR PRIVACY", - "postalCode": "REDACTED FOR PRIVACY", - "country": "REDACTED FOR PRIVACY", - "email": null, - "telephone": null, - "telephoneExt": "REDACTED FOR PRIVACY", - "fax": null, - "faxExt": "REDACTED FOR PRIVACY", - "rawText": "Tech Name: REDACTED FOR PRIVACY|Tech Organization: REDACTED FOR PRIVACY|Tech Street: REDACTED FOR PRIVACY|Tech Street: REDACTED FOR PRIVACY|Tech Street: REDACTED FOR PRIVACY|Tech City: REDACTED FOR PRIVACY|Tech State\/Province: REDACTED FOR PRIVACY|Tech Postal Code: REDACTED FOR PRIVACY|Tech Country: REDACTED FOR PRIVACY|Tech Phone: REDACTED FOR PRIVACY|Tech Phone Ext: REDACTED FOR PRIVACY|Tech Fax: REDACTED FOR PRIVACY|Tech Fax Ext: REDACTED FOR PRIVACY|Tech Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name." - }, - "billingContact": { - "name": null, - "organization": null, - "street": "", - "city": null, - "state": null, - "postalCode": null, - "country": null, - "email": null, - "telephone": null, - "telephoneExt": null, - "fax": null, - "faxExt": null, - "rawText": null - }, - "zoneContact": { - "name": null, - "organization": null, - "street": "", - "city": null, - "state": null, - "postalCode": null, - "country": null, - "email": null, - "telephone": null, - "telephoneExt": null, - "fax": null, - "faxExt": null, - "rawText": null - } - }, - { - "domainName": "coach.sex", - "domainType": "added", - "createdDateISO8601": "2018-08-01T20:47:08+00:00", - "updatedDateISO8601": "2020-09-15T20:48:28+00:00", - "expiresDateISO8601": "2021-08-01T20:47:08+00:00", - "createdDateRaw": "2018-08-01T20:47:08.447Z", - "updatedDateRaw": "2020-09-15T20:48:28.658Z", - "expiresDateRaw": "2021-08-01T20:47:08.447Z", - "audit": { - "createdDate": "2021-03-29T02:03:03+00:00", - "updatedDate": "2021-03-29T02:03:03+00:00" - }, - "nameServers": [ - "ns1.zenbox.pl|ns2.zenbox.pl|" - ], - "whoisServer": "whois.instra.net", - "registrarName": "Instra Corporation Pty Ltd.", - "status": [ - "clientTransferProhibited" - ], - "cleanText": "Domain Name: coach.sex|Registry Domain ID: D425500000050058539-AGRS|Registrar WHOIS Server: whois.instra.net|Registrar URL: www.instra.com|Updated Date: 2020-09-15T20:48:28.658Z|Creation Date: 2018-08-01T20:47:08.447Z|Registry Expiry Date: 2021-08-01T20:47:08.447Z|Registrar: Instra Corporation Pty Ltd.|Registrar IANA ID: 1376|Registrar Abuse Contact Email: support@instra.com|Registrar Abuse Contact Phone: +61.397831800|Domain Status: clientTransferProhibited https:\/\/icann.org\/epp#clientTransferProhibited|Registry Registrant ID: REDACTED FOR PRIVACY|Registrant Name: REDACTED FOR PRIVACY|Registrant Organization: |Registrant Street: REDACTED FOR PRIVACY|Registrant City: REDACTED FOR PRIVACY|Registrant State\/Province: mazowieckie|Registrant Postal Code: REDACTED FOR PRIVACY|Registrant Country: PL|Registrant Phone: REDACTED FOR PRIVACY|Registrant Fax: REDACTED FOR PRIVACY|Registrant Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.|Registry Admin ID: REDACTED FOR PRIVACY|Admin Name: REDACTED FOR PRIVACY|Admin Organization: REDACTED FOR PRIVACY|Admin Street: REDACTED FOR PRIVACY|Admin City: REDACTED FOR PRIVACY|Admin State\/Province: REDACTED FOR PRIVACY|Admin Postal Code: REDACTED FOR PRIVACY|Admin Country: REDACTED FOR PRIVACY|Admin Phone: REDACTED FOR PRIVACY|Admin Fax: REDACTED FOR PRIVACY|Admin Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.|Registry Tech ID: REDACTED FOR PRIVACY|Tech Name: REDACTED FOR PRIVACY|Tech Organization: REDACTED FOR PRIVACY|Tech Street: REDACTED FOR PRIVACY|Tech City: REDACTED FOR PRIVACY|Tech State\/Province: REDACTED FOR PRIVACY|Tech Postal Code: REDACTED FOR PRIVACY|Tech Country: REDACTED FOR PRIVACY|Tech Phone: REDACTED FOR PRIVACY|Tech Fax: REDACTED FOR PRIVACY|Tech Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.|Registry Billing ID: REDACTED FOR PRIVACY|Billing Name: REDACTED FOR PRIVACY|Billing Organization: REDACTED FOR PRIVACY|Billing Street: REDACTED FOR PRIVACY|Billing City: REDACTED FOR PRIVACY|Billing State\/Province: REDACTED FOR PRIVACY|Billing Postal Code: REDACTED FOR PRIVACY|Billing Country: REDACTED FOR PRIVACY|Billing Phone: REDACTED FOR PRIVACY|Billing Fax: REDACTED FOR PRIVACY|Billing Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.|Name Server: ns1.zenbox.pl|Name Server: ns2.zenbox.pl|DNSSEC: unsigned|URL of the ICANN RDDS Inaccuracy Complaint Form: https:\/\/www.icann.org\/wicf\/||>>> Last update of WHOIS database: 2021-03-29T02:02:10.846Z <<<||For more information on domain status codes, please visit https:\/\/icann.org\/epp||The WHOIS information provided in this page has been redacted|in compliance with ICANN's Temporary Specification for gTLD|Registration Data.||The data in this record is provided by Uniregistry for informational|purposes only, and it does not guarantee its accuracy. Uniregistry is|authoritative for whois information in top-level domains it operates|under contract with the Internet Corporation for Assigned Names and|Numbers. Whois information from other top-level domains is provided by|a third-party under license to Uniregistry.||This service is intended only for query-based access. By using this|service, you agree that you will use any data presented only for lawful|purposes and that, under no circumstances will you use (a) data|acquired for the purpose of allowing, enabling, or otherwise supporting|the transmission by e-mail, telephone, facsimile or other|communications mechanism of mass unsolicited, commercial advertising|or solicitations to entities other than your existing customers; or|(b) this service to enable high volume, automated, electronic processes|that send queries or data to the systems of any Registrar or any|Registry except as reasonably necessary to register domain names or|modify existing domain name registrations.||Uniregistry reserves the right to modify these terms at any time. By|submitting this query, you agree to abide by this policy. All rights|reserved.", - "rawText": "Domain Name: coach.sex|Registry Domain ID: D425500000050058539-AGRS|Registrar WHOIS Server: whois.instra.net|Registrar URL: www.instra.com|Updated Date: 2020-09-15T20:48:28.658Z|Creation Date: 2018-08-01T20:47:08.447Z|Registry Expiry Date: 2021-08-01T20:47:08.447Z|Registrar: Instra Corporation Pty Ltd.|Registrar IANA ID: 1376|Registrar Abuse Contact Email: support@instra.com|Registrar Abuse Contact Phone: +61.397831800|Domain Status: clientTransferProhibited https:\/\/icann.org\/epp#clientTransferProhibited|Registry Registrant ID: REDACTED FOR PRIVACY|Registrant Name: REDACTED FOR PRIVACY|Registrant Organization: |Registrant Street: REDACTED FOR PRIVACY|Registrant City: REDACTED FOR PRIVACY|Registrant State\/Province: mazowieckie|Registrant Postal Code: REDACTED FOR PRIVACY|Registrant Country: PL|Registrant Phone: REDACTED FOR PRIVACY|Registrant Fax: REDACTED FOR PRIVACY|Registrant Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.|Registry Admin ID: REDACTED FOR PRIVACY|Admin Name: REDACTED FOR PRIVACY|Admin Organization: REDACTED FOR PRIVACY|Admin Street: REDACTED FOR PRIVACY|Admin City: REDACTED FOR PRIVACY|Admin State\/Province: REDACTED FOR PRIVACY|Admin Postal Code: REDACTED FOR PRIVACY|Admin Country: REDACTED FOR PRIVACY|Admin Phone: REDACTED FOR PRIVACY|Admin Fax: REDACTED FOR PRIVACY|Admin Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.|Registry Tech ID: REDACTED FOR PRIVACY|Tech Name: REDACTED FOR PRIVACY|Tech Organization: REDACTED FOR PRIVACY|Tech Street: REDACTED FOR PRIVACY|Tech City: REDACTED FOR PRIVACY|Tech State\/Province: REDACTED FOR PRIVACY|Tech Postal Code: REDACTED FOR PRIVACY|Tech Country: REDACTED FOR PRIVACY|Tech Phone: REDACTED FOR PRIVACY|Tech Fax: REDACTED FOR PRIVACY|Tech Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.|Registry Billing ID: REDACTED FOR PRIVACY|Billing Name: REDACTED FOR PRIVACY|Billing Organization: REDACTED FOR PRIVACY|Billing Street: REDACTED FOR PRIVACY|Billing City: REDACTED FOR PRIVACY|Billing State\/Province: REDACTED FOR PRIVACY|Billing Postal Code: REDACTED FOR PRIVACY|Billing Country: REDACTED FOR PRIVACY|Billing Phone: REDACTED FOR PRIVACY|Billing Fax: REDACTED FOR PRIVACY|Billing Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.|Name Server: ns1.zenbox.pl|Name Server: ns2.zenbox.pl|DNSSEC: unsigned|URL of the ICANN RDDS Inaccuracy Complaint Form: https:\/\/www.icann.org\/wicf\/||>>> Last update of WHOIS database: 2021-03-29T02:02:10.846Z <<<||For more information on domain status codes, please visit https:\/\/icann.org\/epp||The WHOIS information provided in this page has been redacted|in compliance with ICANN's Temporary Specification for gTLD|Registration Data.||The data in this record is provided by Uniregistry for informational|purposes only, and it does not guarantee its accuracy. Uniregistry is|authoritative for whois information in top-level domains it operates|under contract with the Internet Corporation for Assigned Names and|Numbers. Whois information from other top-level domains is provided by|a third-party under license to Uniregistry.||This service is intended only for query-based access. By using this|service, you agree that you will use any data presented only for lawful|purposes and that, under no circumstances will you use (a) data|acquired for the purpose of allowing, enabling, or otherwise supporting|the transmission by e-mail, telephone, facsimile or other|communications mechanism of mass unsolicited, commercial advertising|or solicitations to entities other than your existing customers; or|(b) this service to enable high volume, automated, electronic processes|that send queries or data to the systems of any Registrar or any|Registry except as reasonably necessary to register domain names or|modify existing domain name registrations.||Uniregistry reserves the right to modify these terms at any time. By|submitting this query, you agree to abide by this policy. All rights|reserved.", - "registrantContact": { - "name": "REDACTED FOR PRIVACY", - "organization": null, - "street": "REDACTED FOR PRIVACY", - "city": "REDACTED FOR PRIVACY", - "state": "mazowieckie", - "postalCode": "REDACTED FOR PRIVACY", - "country": "POLAND", - "email": null, - "telephone": null, - "telephoneExt": null, - "fax": null, - "faxExt": null, - "rawText": "Registrant Name: REDACTED FOR PRIVACY|Registrant Street: REDACTED FOR PRIVACY|Registrant City: REDACTED FOR PRIVACY|Registrant State\/Province: mazowieckie|Registrant Postal Code: REDACTED FOR PRIVACY|Registrant Country: PL|Registrant Phone: REDACTED FOR PRIVACY|Registrant Fax: REDACTED FOR PRIVACY|Registrant Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name." - }, - "administrativeContact": { - "name": "REDACTED FOR PRIVACY", - "organization": "REDACTED FOR PRIVACY", - "street": "REDACTED FOR PRIVACY", - "city": "REDACTED FOR PRIVACY", - "state": "REDACTED FOR PRIVACY", - "postalCode": "REDACTED FOR PRIVACY", - "country": "REDACTED FOR PRIVACY", - "email": null, - "telephone": null, - "telephoneExt": null, - "fax": null, - "faxExt": null, - "rawText": "Admin Name: REDACTED FOR PRIVACY|Admin Organization: REDACTED FOR PRIVACY|Admin Street: REDACTED FOR PRIVACY|Admin City: REDACTED FOR PRIVACY|Admin State\/Province: REDACTED FOR PRIVACY|Admin Postal Code: REDACTED FOR PRIVACY|Admin Country: REDACTED FOR PRIVACY|Admin Phone: REDACTED FOR PRIVACY|Admin Fax: REDACTED FOR PRIVACY|Admin Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name." - }, - "technicalContact": { - "name": "REDACTED FOR PRIVACY", - "organization": "REDACTED FOR PRIVACY", - "street": "REDACTED FOR PRIVACY", - "city": "REDACTED FOR PRIVACY", - "state": "REDACTED FOR PRIVACY", - "postalCode": "REDACTED FOR PRIVACY", - "country": "REDACTED FOR PRIVACY", - "email": null, - "telephone": null, - "telephoneExt": null, - "fax": null, - "faxExt": null, - "rawText": "Tech Name: REDACTED FOR PRIVACY|Tech Organization: REDACTED FOR PRIVACY|Tech Street: REDACTED FOR PRIVACY|Tech City: REDACTED FOR PRIVACY|Tech State\/Province: REDACTED FOR PRIVACY|Tech Postal Code: REDACTED FOR PRIVACY|Tech Country: REDACTED FOR PRIVACY|Tech Phone: REDACTED FOR PRIVACY|Tech Fax: REDACTED FOR PRIVACY|Tech Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name." - }, - "billingContact": { - "name": "REDACTED FOR PRIVACY", - "organization": "REDACTED FOR PRIVACY", - "street": "REDACTED FOR PRIVACY", - "city": "REDACTED FOR PRIVACY", - "state": "REDACTED FOR PRIVACY", - "postalCode": "REDACTED FOR PRIVACY", - "country": "REDACTED FOR PRIVACY", - "email": null, - "telephone": null, - "telephoneExt": null, - "fax": null, - "faxExt": null, - "rawText": "Billing Name: REDACTED FOR PRIVACY|Billing Organization: REDACTED FOR PRIVACY|Billing Street: REDACTED FOR PRIVACY|Billing City: REDACTED FOR PRIVACY|Billing State\/Province: REDACTED FOR PRIVACY|Billing Postal Code: REDACTED FOR PRIVACY|Billing Country: REDACTED FOR PRIVACY|Billing Phone: REDACTED FOR PRIVACY|Billing Fax: REDACTED FOR PRIVACY|Billing Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name." - }, - "zoneContact": { - "name": null, - "organization": null, - "street": "", - "city": null, - "state": null, - "postalCode": null, - "country": null, - "email": null, - "telephone": null, - "telephoneExt": null, - "fax": null, - "faxExt": null, - "rawText": null - } - }, - { - "domainName": "coach.sex", - "domainType": "added", - "createdDateISO8601": "2018-08-01T20:47:08+00:00", - "updatedDateISO8601": "2020-09-01T18:03:20+00:00", - "expiresDateISO8601": "2021-08-01T20:47:08+00:00", - "createdDateRaw": "2018-08-01T20:47:08.447Z", - "updatedDateRaw": "2020-09-01T18:03:20.855Z", - "expiresDateRaw": "2021-08-01T20:47:08.447Z", - "audit": { - "createdDate": "2020-09-10T13:30:33+00:00", - "updatedDate": "2020-09-10T13:30:33+00:00" - }, - "nameServers": [ - "ns2.zenbox.pl|ns1.zenbox.pl|" - ], - "whoisServer": "whois.instra.net", - "registrarName": "Instra Corporation Pty Ltd.", - "status": [ - "clientTransferProhibited", - "autoRenewPeriod" - ], - "cleanText": "Domain Name: coach.sex|Registry Domain ID: D425500000050058539-AGRS|Registrar WHOIS Server: whois.instra.net|Registrar URL: www.instra.com|Updated Date: 2020-09-01T18:03:20.855Z|Creation Date: 2018-08-01T20:47:08.447Z|Registry Expiry Date: 2021-08-01T20:47:08.447Z|Registrar: Instra Corporation Pty Ltd.|Registrar IANA ID: 1376|Registrar Abuse Contact Email: support@instra.com|Registrar Abuse Contact Phone: +61.397831800|Domain Status: clientTransferProhibited https:\/\/icann.org\/epp#clientTransferProhibited|Domain Status: autoRenewPeriod https:\/\/icann.org\/epp#autoRenewPeriod|Registry Registrant ID: REDACTED FOR PRIVACY|Registrant Name: REDACTED FOR PRIVACY|Registrant Organization: |Registrant Street: REDACTED FOR PRIVACY|Registrant City: REDACTED FOR PRIVACY|Registrant State\/Province: mazowieckie|Registrant Postal Code: REDACTED FOR PRIVACY|Registrant Country: PL|Registrant Phone: REDACTED FOR PRIVACY|Registrant Fax: REDACTED FOR PRIVACY|Registrant Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.|Registry Admin ID: REDACTED FOR PRIVACY|Admin Name: REDACTED FOR PRIVACY|Admin Organization: REDACTED FOR PRIVACY|Admin Street: REDACTED FOR PRIVACY|Admin City: REDACTED FOR PRIVACY|Admin State\/Province: REDACTED FOR PRIVACY|Admin Postal Code: REDACTED FOR PRIVACY|Admin Country: REDACTED FOR PRIVACY|Admin Phone: REDACTED FOR PRIVACY|Admin Fax: REDACTED FOR PRIVACY|Admin Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.|Registry Tech ID: REDACTED FOR PRIVACY|Tech Name: REDACTED FOR PRIVACY|Tech Organization: REDACTED FOR PRIVACY|Tech Street: REDACTED FOR PRIVACY|Tech City: REDACTED FOR PRIVACY|Tech State\/Province: REDACTED FOR PRIVACY|Tech Postal Code: REDACTED FOR PRIVACY|Tech Country: REDACTED FOR PRIVACY|Tech Phone: REDACTED FOR PRIVACY|Tech Fax: REDACTED FOR PRIVACY|Tech Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.|Registry Billing ID: REDACTED FOR PRIVACY|Billing Name: REDACTED FOR PRIVACY|Billing Organization: REDACTED FOR PRIVACY|Billing Street: REDACTED FOR PRIVACY|Billing City: REDACTED FOR PRIVACY|Billing State\/Province: REDACTED FOR PRIVACY|Billing Postal Code: REDACTED FOR PRIVACY|Billing Country: REDACTED FOR PRIVACY|Billing Phone: REDACTED FOR PRIVACY|Billing Fax: REDACTED FOR PRIVACY|Billing Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.|Name Server: ns2.zenbox.pl|Name Server: ns1.zenbox.pl|DNSSEC: unsigned|URL of the ICANN RDDS Inaccuracy Complaint Form: https:\/\/www.icann.org\/wicf\/||>>> Last update of WHOIS database: 2020-09-10T13:29:48.077Z <<<||For more information on domain status codes, please visit https:\/\/icann.org\/epp||The WHOIS information provided in this page has been redacted|in compliance with ICANN's Temporary Specification for gTLD|Registration Data.||The data in this record is provided by Uniregistry for informational|purposes only, and it does not guarantee its accuracy. Uniregistry is|authoritative for whois information in top-level domains it operates|under contract with the Internet Corporation for Assigned Names and|Numbers. Whois information from other top-level domains is provided by|a third-party under license to Uniregistry.||This service is intended only for query-based access. By using this|service, you agree that you will use any data presented only for lawful|purposes and that, under no circumstances will you use (a) data|acquired for the purpose of allowing, enabling, or otherwise supporting|the transmission by e-mail, telephone, facsimile or other|communications mechanism of mass unsolicited, commercial advertising|or solicitations to entities other than your existing customers; or|(b) this service to enable high volume, automated, electronic processes|that send queries or data to the systems of any Registrar or any|Registry except as reasonably necessary to register domain names or|modify existing domain name registrations.||Uniregistry reserves the right to modify these terms at any time. By|submitting this query, you agree to abide by this policy. All rights|reserved.", - "rawText": "Domain Name: coach.sex|Registry Domain ID: D425500000050058539-AGRS|Registrar WHOIS Server: whois.instra.net|Registrar URL: www.instra.com|Updated Date: 2020-09-01T18:03:20.855Z|Creation Date: 2018-08-01T20:47:08.447Z|Registry Expiry Date: 2021-08-01T20:47:08.447Z|Registrar: Instra Corporation Pty Ltd.|Registrar IANA ID: 1376|Registrar Abuse Contact Email: support@instra.com|Registrar Abuse Contact Phone: +61.397831800|Domain Status: clientTransferProhibited https:\/\/icann.org\/epp#clientTransferProhibited|Domain Status: autoRenewPeriod https:\/\/icann.org\/epp#autoRenewPeriod|Registry Registrant ID: REDACTED FOR PRIVACY|Registrant Name: REDACTED FOR PRIVACY|Registrant Organization: |Registrant Street: REDACTED FOR PRIVACY|Registrant City: REDACTED FOR PRIVACY|Registrant State\/Province: mazowieckie|Registrant Postal Code: REDACTED FOR PRIVACY|Registrant Country: PL|Registrant Phone: REDACTED FOR PRIVACY|Registrant Fax: REDACTED FOR PRIVACY|Registrant Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.|Registry Admin ID: REDACTED FOR PRIVACY|Admin Name: REDACTED FOR PRIVACY|Admin Organization: REDACTED FOR PRIVACY|Admin Street: REDACTED FOR PRIVACY|Admin City: REDACTED FOR PRIVACY|Admin State\/Province: REDACTED FOR PRIVACY|Admin Postal Code: REDACTED FOR PRIVACY|Admin Country: REDACTED FOR PRIVACY|Admin Phone: REDACTED FOR PRIVACY|Admin Fax: REDACTED FOR PRIVACY|Admin Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.|Registry Tech ID: REDACTED FOR PRIVACY|Tech Name: REDACTED FOR PRIVACY|Tech Organization: REDACTED FOR PRIVACY|Tech Street: REDACTED FOR PRIVACY|Tech City: REDACTED FOR PRIVACY|Tech State\/Province: REDACTED FOR PRIVACY|Tech Postal Code: REDACTED FOR PRIVACY|Tech Country: REDACTED FOR PRIVACY|Tech Phone: REDACTED FOR PRIVACY|Tech Fax: REDACTED FOR PRIVACY|Tech Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.|Registry Billing ID: REDACTED FOR PRIVACY|Billing Name: REDACTED FOR PRIVACY|Billing Organization: REDACTED FOR PRIVACY|Billing Street: REDACTED FOR PRIVACY|Billing City: REDACTED FOR PRIVACY|Billing State\/Province: REDACTED FOR PRIVACY|Billing Postal Code: REDACTED FOR PRIVACY|Billing Country: REDACTED FOR PRIVACY|Billing Phone: REDACTED FOR PRIVACY|Billing Fax: REDACTED FOR PRIVACY|Billing Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.|Name Server: ns2.zenbox.pl|Name Server: ns1.zenbox.pl|DNSSEC: unsigned|URL of the ICANN RDDS Inaccuracy Complaint Form: https:\/\/www.icann.org\/wicf\/||>>> Last update of WHOIS database: 2020-09-10T13:29:48.077Z <<<||For more information on domain status codes, please visit https:\/\/icann.org\/epp||The WHOIS information provided in this page has been redacted|in compliance with ICANN's Temporary Specification for gTLD|Registration Data.||The data in this record is provided by Uniregistry for informational|purposes only, and it does not guarantee its accuracy. Uniregistry is|authoritative for whois information in top-level domains it operates|under contract with the Internet Corporation for Assigned Names and|Numbers. Whois information from other top-level domains is provided by|a third-party under license to Uniregistry.||This service is intended only for query-based access. By using this|service, you agree that you will use any data presented only for lawful|purposes and that, under no circumstances will you use (a) data|acquired for the purpose of allowing, enabling, or otherwise supporting|the transmission by e-mail, telephone, facsimile or other|communications mechanism of mass unsolicited, commercial advertising|or solicitations to entities other than your existing customers; or|(b) this service to enable high volume, automated, electronic processes|that send queries or data to the systems of any Registrar or any|Registry except as reasonably necessary to register domain names or|modify existing domain name registrations.||Uniregistry reserves the right to modify these terms at any time. By|submitting this query, you agree to abide by this policy. All rights|reserved.", - "registrantContact": { - "name": "REDACTED FOR PRIVACY", - "organization": null, - "street": "REDACTED FOR PRIVACY", - "city": "REDACTED FOR PRIVACY", - "state": "mazowieckie", - "postalCode": "REDACTED FOR PRIVACY", - "country": "POLAND", - "email": null, - "telephone": null, - "telephoneExt": null, - "fax": null, - "faxExt": null, - "rawText": "Registrant Name: REDACTED FOR PRIVACY|Registrant Street: REDACTED FOR PRIVACY|Registrant City: REDACTED FOR PRIVACY|Registrant State\/Province: mazowieckie|Registrant Postal Code: REDACTED FOR PRIVACY|Registrant Country: PL|Registrant Phone: REDACTED FOR PRIVACY|Registrant Fax: REDACTED FOR PRIVACY|Registrant Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name." - }, - "administrativeContact": { - "name": "REDACTED FOR PRIVACY", - "organization": "REDACTED FOR PRIVACY", - "street": "REDACTED FOR PRIVACY", - "city": "REDACTED FOR PRIVACY", - "state": "REDACTED FOR PRIVACY", - "postalCode": "REDACTED FOR PRIVACY", - "country": "REDACTED FOR PRIVACY", - "email": null, - "telephone": null, - "telephoneExt": null, - "fax": null, - "faxExt": null, - "rawText": "Admin Name: REDACTED FOR PRIVACY|Admin Organization: REDACTED FOR PRIVACY|Admin Street: REDACTED FOR PRIVACY|Admin City: REDACTED FOR PRIVACY|Admin State\/Province: REDACTED FOR PRIVACY|Admin Postal Code: REDACTED FOR PRIVACY|Admin Country: REDACTED FOR PRIVACY|Admin Phone: REDACTED FOR PRIVACY|Admin Fax: REDACTED FOR PRIVACY|Admin Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name." - }, - "technicalContact": { - "name": "REDACTED FOR PRIVACY", - "organization": "REDACTED FOR PRIVACY", - "street": "REDACTED FOR PRIVACY", - "city": "REDACTED FOR PRIVACY", - "state": "REDACTED FOR PRIVACY", - "postalCode": "REDACTED FOR PRIVACY", - "country": "REDACTED FOR PRIVACY", - "email": null, - "telephone": null, - "telephoneExt": null, - "fax": null, - "faxExt": null, - "rawText": "Tech Name: REDACTED FOR PRIVACY|Tech Organization: REDACTED FOR PRIVACY|Tech Street: REDACTED FOR PRIVACY|Tech City: REDACTED FOR PRIVACY|Tech State\/Province: REDACTED FOR PRIVACY|Tech Postal Code: REDACTED FOR PRIVACY|Tech Country: REDACTED FOR PRIVACY|Tech Phone: REDACTED FOR PRIVACY|Tech Fax: REDACTED FOR PRIVACY|Tech Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name." - }, - "billingContact": { - "name": "REDACTED FOR PRIVACY", - "organization": "REDACTED FOR PRIVACY", - "street": "REDACTED FOR PRIVACY", - "city": "REDACTED FOR PRIVACY", - "state": "REDACTED FOR PRIVACY", - "postalCode": "REDACTED FOR PRIVACY", - "country": "REDACTED FOR PRIVACY", - "email": null, - "telephone": null, - "telephoneExt": null, - "fax": null, - "faxExt": null, - "rawText": "Billing Name: REDACTED FOR PRIVACY|Billing Organization: REDACTED FOR PRIVACY|Billing Street: REDACTED FOR PRIVACY|Billing City: REDACTED FOR PRIVACY|Billing State\/Province: REDACTED FOR PRIVACY|Billing Postal Code: REDACTED FOR PRIVACY|Billing Country: REDACTED FOR PRIVACY|Billing Phone: REDACTED FOR PRIVACY|Billing Fax: REDACTED FOR PRIVACY|Billing Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name." - }, - "zoneContact": { - "name": null, - "organization": null, - "street": "", - "city": null, - "state": null, - "postalCode": null, - "country": null, - "email": null, - "telephone": null, - "telephoneExt": null, - "fax": null, - "faxExt": null, - "rawText": null - } - }, - { - "domainName": "coach.sex", - "domainType": "added", - "createdDateISO8601": "2018-08-01T20:47:08+00:00", - "updatedDateISO8601": "2020-09-01T18:03:20+00:00", - "expiresDateISO8601": "2021-08-01T20:47:08+00:00", - "createdDateRaw": "2018-08-01T20:47:08.447Z", - "updatedDateRaw": "2020-09-01T18:03:20.855Z", - "expiresDateRaw": "2021-08-01T20:47:08.447Z", - "audit": { - "createdDate": "2020-09-10T13:30:33+00:00", - "updatedDate": "2020-09-10T13:30:33+00:00" - }, - "nameServers": [ - "ns2.zenbox.pl", - "ns1.zenbox.pl" - ], - "whoisServer": "whois.instra.net", - "registrarName": "Instra Corporation Pty Ltd.", - "status": [ - "clientTransferProhibited", - "autoRenewPeriod" - ], - "cleanText": "Domain Name: coach.sex\nRegistry Domain ID: D425500000050058539-AGRS\nRegistrar WHOIS Server: whois.instra.net\nRegistrar URL: www.instra.com\nUpdated Date: 2020-09-01T18:03:20.855Z\nCreation Date: 2018-08-01T20:47:08.447Z\nRegistry Expiry Date: 2021-08-01T20:47:08.447Z\nRegistrar: Instra Corporation Pty Ltd.\nRegistrar IANA ID: 1376\nRegistrar Abuse Contact Email: support@instra.com\nRegistrar Abuse Contact Phone: +61.397831800\nDomain Status: clientTransferProhibited https:\/\/icann.org\/epp#clientTransferProhibited\nDomain Status: autoRenewPeriod https:\/\/icann.org\/epp#autoRenewPeriod\nRegistry Registrant ID: REDACTED FOR PRIVACY\nRegistrant Name: REDACTED FOR PRIVACY\nRegistrant Organization: \nRegistrant Street: REDACTED FOR PRIVACY\nRegistrant City: REDACTED FOR PRIVACY\nRegistrant State\/Province: mazowieckie\nRegistrant Postal Code: REDACTED FOR PRIVACY\nRegistrant Country: PL\nRegistrant Phone: REDACTED FOR PRIVACY\nRegistrant Fax: REDACTED FOR PRIVACY\nRegistrant Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.\nRegistry Admin ID: REDACTED FOR PRIVACY\nAdmin Name: REDACTED FOR PRIVACY\nAdmin Organization: REDACTED FOR PRIVACY\nAdmin Street: REDACTED FOR PRIVACY\nAdmin City: REDACTED FOR PRIVACY\nAdmin State\/Province: REDACTED FOR PRIVACY\nAdmin Postal Code: REDACTED FOR PRIVACY\nAdmin Country: REDACTED FOR PRIVACY\nAdmin Phone: REDACTED FOR PRIVACY\nAdmin Fax: REDACTED FOR PRIVACY\nAdmin Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.\nRegistry Tech ID: REDACTED FOR PRIVACY\nTech Name: REDACTED FOR PRIVACY\nTech Organization: REDACTED FOR PRIVACY\nTech Street: REDACTED FOR PRIVACY\nTech City: REDACTED FOR PRIVACY\nTech State\/Province: REDACTED FOR PRIVACY\nTech Postal Code: REDACTED FOR PRIVACY\nTech Country: REDACTED FOR PRIVACY\nTech Phone: REDACTED FOR PRIVACY\nTech Fax: REDACTED FOR PRIVACY\nTech Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.\nRegistry Billing ID: REDACTED FOR PRIVACY\nBilling Name: REDACTED FOR PRIVACY\nBilling Organization: REDACTED FOR PRIVACY\nBilling Street: REDACTED FOR PRIVACY\nBilling City: REDACTED FOR PRIVACY\nBilling State\/Province: REDACTED FOR PRIVACY\nBilling Postal Code: REDACTED FOR PRIVACY\nBilling Country: REDACTED FOR PRIVACY\nBilling Phone: REDACTED FOR PRIVACY\nBilling Fax: REDACTED FOR PRIVACY\nBilling Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.\nName Server: ns2.zenbox.pl\nName Server: ns1.zenbox.pl\nDNSSEC: unsigned\nURL of the ICANN RDDS Inaccuracy Complaint Form: https:\/\/www.icann.org\/wicf\/\n\n>>> Last update of WHOIS database: 2020-09-10T13:29:48.077Z <<<\n\nFor more information on domain status codes, please visit https:\/\/icann.org\/epp\n\nThe WHOIS information provided in this page has been redacted\nin compliance with ICANN's Temporary Specification for gTLD\nRegistration Data.\n\nThe data in this record is provided by Uniregistry for informational\npurposes only, and it does not guarantee its accuracy. Uniregistry is\nauthoritative for whois information in top-level domains it operates\nunder contract with the Internet Corporation for Assigned Names and\nNumbers. Whois information from other top-level domains is provided by\na third-party under license to Uniregistry.\n\nThis service is intended only for query-based access. By using this\nservice, you agree that you will use any data presented only for lawful\npurposes and that, under no circumstances will you use (a) data\nacquired for the purpose of allowing, enabling, or otherwise supporting\nthe transmission by e-mail, telephone, facsimile or other\ncommunications mechanism of mass unsolicited, commercial advertising\nor solicitations to entities other than your existing customers; or\n(b) this service to enable high volume, automated, electronic processes\nthat send queries or data to the systems of any Registrar or any\nRegistry except as reasonably necessary to register domain names or\nmodify existing domain name registrations.\n\nUniregistry reserves the right to modify these terms at any time. By\nsubmitting this query, you agree to abide by this policy. All rights\nreserved.", - "rawText": "Domain Name: coach.sex\nRegistry Domain ID: D425500000050058539-AGRS\nRegistrar WHOIS Server: whois.instra.net\nRegistrar URL: www.instra.com\nUpdated Date: 2020-09-01T18:03:20.855Z\nCreation Date: 2018-08-01T20:47:08.447Z\nRegistry Expiry Date: 2021-08-01T20:47:08.447Z\nRegistrar: Instra Corporation Pty Ltd.\nRegistrar IANA ID: 1376\nRegistrar Abuse Contact Email: support@instra.com\nRegistrar Abuse Contact Phone: +61.397831800\nDomain Status: clientTransferProhibited https:\/\/icann.org\/epp#clientTransferProhibited\nDomain Status: autoRenewPeriod https:\/\/icann.org\/epp#autoRenewPeriod\nRegistry Registrant ID: REDACTED FOR PRIVACY\nRegistrant Name: REDACTED FOR PRIVACY\nRegistrant Organization: \nRegistrant Street: REDACTED FOR PRIVACY\nRegistrant City: REDACTED FOR PRIVACY\nRegistrant State\/Province: mazowieckie\nRegistrant Postal Code: REDACTED FOR PRIVACY\nRegistrant Country: PL\nRegistrant Phone: REDACTED FOR PRIVACY\nRegistrant Fax: REDACTED FOR PRIVACY\nRegistrant Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.\nRegistry Admin ID: REDACTED FOR PRIVACY\nAdmin Name: REDACTED FOR PRIVACY\nAdmin Organization: REDACTED FOR PRIVACY\nAdmin Street: REDACTED FOR PRIVACY\nAdmin City: REDACTED FOR PRIVACY\nAdmin State\/Province: REDACTED FOR PRIVACY\nAdmin Postal Code: REDACTED FOR PRIVACY\nAdmin Country: REDACTED FOR PRIVACY\nAdmin Phone: REDACTED FOR PRIVACY\nAdmin Fax: REDACTED FOR PRIVACY\nAdmin Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.\nRegistry Tech ID: REDACTED FOR PRIVACY\nTech Name: REDACTED FOR PRIVACY\nTech Organization: REDACTED FOR PRIVACY\nTech Street: REDACTED FOR PRIVACY\nTech City: REDACTED FOR PRIVACY\nTech State\/Province: REDACTED FOR PRIVACY\nTech Postal Code: REDACTED FOR PRIVACY\nTech Country: REDACTED FOR PRIVACY\nTech Phone: REDACTED FOR PRIVACY\nTech Fax: REDACTED FOR PRIVACY\nTech Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.\nRegistry Billing ID: REDACTED FOR PRIVACY\nBilling Name: REDACTED FOR PRIVACY\nBilling Organization: REDACTED FOR PRIVACY\nBilling Street: REDACTED FOR PRIVACY\nBilling City: REDACTED FOR PRIVACY\nBilling State\/Province: REDACTED FOR PRIVACY\nBilling Postal Code: REDACTED FOR PRIVACY\nBilling Country: REDACTED FOR PRIVACY\nBilling Phone: REDACTED FOR PRIVACY\nBilling Fax: REDACTED FOR PRIVACY\nBilling Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.\nName Server: ns2.zenbox.pl\nName Server: ns1.zenbox.pl\nDNSSEC: unsigned\nURL of the ICANN RDDS Inaccuracy Complaint Form: https:\/\/www.icann.org\/wicf\/\n\n>>> Last update of WHOIS database: 2020-09-10T13:29:48.077Z <<<\n\nFor more information on domain status codes, please visit https:\/\/icann.org\/epp\n\nThe WHOIS information provided in this page has been redacted\nin compliance with ICANN's Temporary Specification for gTLD\nRegistration Data.\n\nThe data in this record is provided by Uniregistry for informational\npurposes only, and it does not guarantee its accuracy. Uniregistry is\nauthoritative for whois information in top-level domains it operates\nunder contract with the Internet Corporation for Assigned Names and\nNumbers. Whois information from other top-level domains is provided by\na third-party under license to Uniregistry.\n\nThis service is intended only for query-based access. By using this\nservice, you agree that you will use any data presented only for lawful\npurposes and that, under no circumstances will you use (a) data\nacquired for the purpose of allowing, enabling, or otherwise supporting\nthe transmission by e-mail, telephone, facsimile or other\ncommunications mechanism of mass unsolicited, commercial advertising\nor solicitations to entities other than your existing customers; or\n(b) this service to enable high volume, automated, electronic processes\nthat send queries or data to the systems of any Registrar or any\nRegistry except as reasonably necessary to register domain names or\nmodify existing domain name registrations.\n\nUniregistry reserves the right to modify these terms at any time. By\nsubmitting this query, you agree to abide by this policy. All rights\nreserved.", - "registrantContact": { - "name": "REDACTED FOR PRIVACY", - "organization": null, - "street": "REDACTED FOR PRIVACY", - "city": "REDACTED FOR PRIVACY", - "state": "mazowieckie", - "postalCode": "REDACTED FOR PRIVACY", - "country": "POLAND", - "email": null, - "telephone": null, - "telephoneExt": null, - "fax": null, - "faxExt": null, - "rawText": "Registrant Name: REDACTED FOR PRIVACY|Registrant Street: REDACTED FOR PRIVACY|Registrant City: REDACTED FOR PRIVACY|Registrant State\/Province: mazowieckie|Registrant Postal Code: REDACTED FOR PRIVACY|Registrant Country: PL|Registrant Phone: REDACTED FOR PRIVACY|Registrant Fax: REDACTED FOR PRIVACY|Registrant Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name." - }, - "administrativeContact": { - "name": "REDACTED FOR PRIVACY", - "organization": "REDACTED FOR PRIVACY", - "street": "REDACTED FOR PRIVACY", - "city": "REDACTED FOR PRIVACY", - "state": "REDACTED FOR PRIVACY", - "postalCode": "REDACTED FOR PRIVACY", - "country": "REDACTED FOR PRIVACY", - "email": null, - "telephone": null, - "telephoneExt": null, - "fax": null, - "faxExt": null, - "rawText": "Admin Name: REDACTED FOR PRIVACY|Admin Organization: REDACTED FOR PRIVACY|Admin Street: REDACTED FOR PRIVACY|Admin City: REDACTED FOR PRIVACY|Admin State\/Province: REDACTED FOR PRIVACY|Admin Postal Code: REDACTED FOR PRIVACY|Admin Country: REDACTED FOR PRIVACY|Admin Phone: REDACTED FOR PRIVACY|Admin Fax: REDACTED FOR PRIVACY|Admin Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name." - }, - "technicalContact": { - "name": "REDACTED FOR PRIVACY", - "organization": "REDACTED FOR PRIVACY", - "street": "REDACTED FOR PRIVACY", - "city": "REDACTED FOR PRIVACY", - "state": "REDACTED FOR PRIVACY", - "postalCode": "REDACTED FOR PRIVACY", - "country": "REDACTED FOR PRIVACY", - "email": null, - "telephone": null, - "telephoneExt": null, - "fax": null, - "faxExt": null, - "rawText": "Tech Name: REDACTED FOR PRIVACY|Tech Organization: REDACTED FOR PRIVACY|Tech Street: REDACTED FOR PRIVACY|Tech City: REDACTED FOR PRIVACY|Tech State\/Province: REDACTED FOR PRIVACY|Tech Postal Code: REDACTED FOR PRIVACY|Tech Country: REDACTED FOR PRIVACY|Tech Phone: REDACTED FOR PRIVACY|Tech Fax: REDACTED FOR PRIVACY|Tech Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name." - }, - "billingContact": { - "name": "REDACTED FOR PRIVACY", - "organization": "REDACTED FOR PRIVACY", - "street": "REDACTED FOR PRIVACY", - "city": "REDACTED FOR PRIVACY", - "state": "REDACTED FOR PRIVACY", - "postalCode": "REDACTED FOR PRIVACY", - "country": "REDACTED FOR PRIVACY", - "email": null, - "telephone": null, - "telephoneExt": null, - "fax": null, - "faxExt": null, - "rawText": "Billing Name: REDACTED FOR PRIVACY|Billing Organization: REDACTED FOR PRIVACY|Billing Street: REDACTED FOR PRIVACY|Billing City: REDACTED FOR PRIVACY|Billing State\/Province: REDACTED FOR PRIVACY|Billing Postal Code: REDACTED FOR PRIVACY|Billing Country: REDACTED FOR PRIVACY|Billing Phone: REDACTED FOR PRIVACY|Billing Fax: REDACTED FOR PRIVACY|Billing Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name." - }, - "zoneContact": { - "name": null, - "organization": null, - "street": "", - "city": null, - "state": null, - "postalCode": null, - "country": null, - "email": null, - "telephone": null, - "telephoneExt": null, - "fax": null, - "faxExt": null, - "rawText": null - } - }, - { - "domainName": "coach.sex", - "domainType": "added", - "createdDateISO8601": "2018-08-01T20:47:08+00:00", - "updatedDateISO8601": "2020-09-01T18:03:20+00:00", - "expiresDateISO8601": "2021-08-01T20:47:08+00:00", - "createdDateRaw": "2018-08-01T20:47:08.447Z", - "updatedDateRaw": "2020-09-01T18:03:20.855Z", - "expiresDateRaw": "2021-08-01T20:47:08.447Z", - "audit": { - "createdDate": "2020-09-03T16:58:47+00:00", - "updatedDate": "2020-09-03T16:58:47+00:00" - }, - "nameServers": [ - "ns2.zenbox.pl", - "ns1.zenbox.pl" - ], - "whoisServer": "whois.instra.net", - "registrarName": "Instra Corporation Pty Ltd.", - "status": [ - "clientTransferProhibited", - "autoRenewPeriod" - ], - "cleanText": "Domain Name: coach.sex\nRegistrar WHOIS Server: whois.instra.net\nRegistrar URL: www.instra.com\nUpdated Date: 2020-09-01T18:03:20.855Z\nCreation Date: 2018-08-01T20:47:08.447Z\nRegistry Expiry Date: 2021-08-01T20:47:08.447Z\nRegistrar: Instra Corporation Pty Ltd.\nRegistrar IANA ID: 1376\nRegistrar Abuse Contact Email: support@instra.com\nRegistrar Abuse Contact Phone: +61.397831800\nDomain Status: clientTransferProhibited https:\/\/icann.org\/epp#clientTransferProhibited\nDomain Status: autoRenewPeriod https:\/\/icann.org\/epp#autoRenewPeriod\nRegistrant Name: REDACTED FOR PRIVACY\nRegistrant Street: REDACTED FOR PRIVACY\nRegistrant City: REDACTED FOR PRIVACY\nRegistrant State\/Province: mazowieckie\nRegistrant Postal Code: REDACTED FOR PRIVACY\nRegistrant Country: PL\nRegistrant Phone: REDACTED FOR PRIVACY\nRegistrant Fax: REDACTED FOR PRIVACY\nRegistrant Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.\nAdmin Name: REDACTED FOR PRIVACY\nAdmin Organization: REDACTED FOR PRIVACY\nAdmin Street: REDACTED FOR PRIVACY\nAdmin City: REDACTED FOR PRIVACY\nAdmin State\/Province: REDACTED FOR PRIVACY\nAdmin Postal Code: REDACTED FOR PRIVACY\nAdmin Country: REDACTED FOR PRIVACY\nAdmin Phone: REDACTED FOR PRIVACY\nAdmin Fax: REDACTED FOR PRIVACY\nAdmin Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.\nTech Name: REDACTED FOR PRIVACY\nTech Organization: REDACTED FOR PRIVACY\nTech Street: REDACTED FOR PRIVACY\nTech City: REDACTED FOR PRIVACY\nTech State\/Province: REDACTED FOR PRIVACY\nTech Postal Code: REDACTED FOR PRIVACY\nTech Country: REDACTED FOR PRIVACY\nTech Phone: REDACTED FOR PRIVACY\nTech Fax: REDACTED FOR PRIVACY\nTech Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.\nBilling Name: REDACTED FOR PRIVACY\nBilling Organization: REDACTED FOR PRIVACY\nBilling Street: REDACTED FOR PRIVACY\nBilling City: REDACTED FOR PRIVACY\nBilling State\/Province: REDACTED FOR PRIVACY\nBilling Postal Code: REDACTED FOR PRIVACY\nBilling Country: REDACTED FOR PRIVACY\nBilling Phone: REDACTED FOR PRIVACY\nBilling Fax: REDACTED FOR PRIVACY\nBilling Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.\nName Server: ns2.zenbox.pl\nName Server: ns1.zenbox.pl\n", - "rawText": "Domain Name: coach.sex\nRegistry Domain ID: D425500000050058539-AGRS\nRegistrar WHOIS Server: whois.instra.net\nRegistrar URL: www.instra.com\nUpdated Date: 2020-09-01T18:03:20.855Z\nCreation Date: 2018-08-01T20:47:08.447Z\nRegistry Expiry Date: 2021-08-01T20:47:08.447Z\nRegistrar: Instra Corporation Pty Ltd.\nRegistrar IANA ID: 1376\nRegistrar Abuse Contact Email: support@instra.com\nRegistrar Abuse Contact Phone: +61.397831800\nDomain Status: clientTransferProhibited https:\/\/icann.org\/epp#clientTransferProhibited\nDomain Status: autoRenewPeriod https:\/\/icann.org\/epp#autoRenewPeriod\nRegistry Registrant ID: REDACTED FOR PRIVACY\nRegistrant Name: REDACTED FOR PRIVACY\nRegistrant Organization: \nRegistrant Street: REDACTED FOR PRIVACY\nRegistrant City: REDACTED FOR PRIVACY\nRegistrant State\/Province: mazowieckie\nRegistrant Postal Code: REDACTED FOR PRIVACY\nRegistrant Country: PL\nRegistrant Phone: REDACTED FOR PRIVACY\nRegistrant Fax: REDACTED FOR PRIVACY\nRegistrant Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.\nRegistry Admin ID: REDACTED FOR PRIVACY\nAdmin Name: REDACTED FOR PRIVACY\nAdmin Organization: REDACTED FOR PRIVACY\nAdmin Street: REDACTED FOR PRIVACY\nAdmin City: REDACTED FOR PRIVACY\nAdmin State\/Province: REDACTED FOR PRIVACY\nAdmin Postal Code: REDACTED FOR PRIVACY\nAdmin Country: REDACTED FOR PRIVACY\nAdmin Phone: REDACTED FOR PRIVACY\nAdmin Fax: REDACTED FOR PRIVACY\nAdmin Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.\nRegistry Tech ID: REDACTED FOR PRIVACY\nTech Name: REDACTED FOR PRIVACY\nTech Organization: REDACTED FOR PRIVACY\nTech Street: REDACTED FOR PRIVACY\nTech City: REDACTED FOR PRIVACY\nTech State\/Province: REDACTED FOR PRIVACY\nTech Postal Code: REDACTED FOR PRIVACY\nTech Country: REDACTED FOR PRIVACY\nTech Phone: REDACTED FOR PRIVACY\nTech Fax: REDACTED FOR PRIVACY\nTech Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.\nRegistry Billing ID: REDACTED FOR PRIVACY\nBilling Name: REDACTED FOR PRIVACY\nBilling Organization: REDACTED FOR PRIVACY\nBilling Street: REDACTED FOR PRIVACY\nBilling City: REDACTED FOR PRIVACY\nBilling State\/Province: REDACTED FOR PRIVACY\nBilling Postal Code: REDACTED FOR PRIVACY\nBilling Country: REDACTED FOR PRIVACY\nBilling Phone: REDACTED FOR PRIVACY\nBilling Fax: REDACTED FOR PRIVACY\nBilling Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.\nName Server: ns2.zenbox.pl\nName Server: ns1.zenbox.pl\nDNSSEC: unsigned\nURL of the ICANN RDDS Inaccuracy Complaint Form: https:\/\/www.icann.org\/wicf\/\n\n>>> Last update of WHOIS database: 2020-09-03T16:58:43.794Z <<<\n\nFor more information on domain status codes, please visit https:\/\/icann.org\/epp\n\nThe WHOIS information provided in this page has been redacted\nin compliance with ICANN's Temporary Specification for gTLD\nRegistration Data.\n\nThe data in this record is provided by Uniregistry for informational\npurposes only, and it does not guarantee its accuracy. Uniregistry is\nauthoritative for whois information in top-level domains it operates\nunder contract with the Internet Corporation for Assigned Names and\nNumbers. Whois information from other top-level domains is provided by\na third-party under license to Uniregistry.\n\nThis service is intended only for query-based access. By using this\nservice, you agree that you will use any data presented only for lawful\npurposes and that, under no circumstances will you use (a) data\nacquired for the purpose of allowing, enabling, or otherwise supporting\nthe transmission by e-mail, telephone, facsimile or other\ncommunications mechanism of mass unsolicited, commercial advertising\nor solicitations to entities other than your existing customers; or\n(b) this service to enable high volume, automated, electronic processes\nthat send queries or data to the systems of any Registrar or any\nRegistry except as reasonably necessary to register domain names or\nmodify existing domain name registrations.\n\nUniregistry reserves the right to modify these terms at any time. By\nsubmitting this query, you agree to abide by this policy. All rights\nreserved.", - "registrantContact": { - "name": "REDACTED FOR PRIVACY", - "organization": null, - "street": "REDACTED FOR PRIVACY", - "city": "REDACTED FOR PRIVACY", - "state": "mazowieckie", - "postalCode": "REDACTED FOR PRIVACY", - "country": "POLAND", - "email": null, - "telephone": "", - "telephoneExt": null, - "fax": "", - "faxExt": null, - "rawText": "Registrant Name: REDACTED FOR PRIVACY\nRegistrant Street: REDACTED FOR PRIVACY\nRegistrant City: REDACTED FOR PRIVACY\nRegistrant State\/Province: mazowieckie\nRegistrant Postal Code: REDACTED FOR PRIVACY\nRegistrant Country: PL\nRegistrant Phone: REDACTED FOR PRIVACY\nRegistrant Fax: REDACTED FOR PRIVACY\nRegistrant Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name." - }, - "administrativeContact": { - "name": "REDACTED FOR PRIVACY", - "organization": "REDACTED FOR PRIVACY", - "street": "REDACTED FOR PRIVACY", - "city": "REDACTED FOR PRIVACY", - "state": "REDACTED FOR PRIVACY", - "postalCode": "REDACTED FOR PRIVACY", - "country": "REDACTED FOR PRIVACY", - "email": null, - "telephone": "", - "telephoneExt": null, - "fax": "", - "faxExt": null, - "rawText": "Admin Name: REDACTED FOR PRIVACY\nAdmin Organization: REDACTED FOR PRIVACY\nAdmin Street: REDACTED FOR PRIVACY\nAdmin City: REDACTED FOR PRIVACY\nAdmin State\/Province: REDACTED FOR PRIVACY\nAdmin Postal Code: REDACTED FOR PRIVACY\nAdmin Country: REDACTED FOR PRIVACY\nAdmin Phone: REDACTED FOR PRIVACY\nAdmin Fax: REDACTED FOR PRIVACY\nAdmin Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name." - }, - "technicalContact": { - "name": "REDACTED FOR PRIVACY", - "organization": "REDACTED FOR PRIVACY", - "street": "REDACTED FOR PRIVACY", - "city": "REDACTED FOR PRIVACY", - "state": "REDACTED FOR PRIVACY", - "postalCode": "REDACTED FOR PRIVACY", - "country": "REDACTED FOR PRIVACY", - "email": null, - "telephone": "", - "telephoneExt": null, - "fax": "", - "faxExt": null, - "rawText": "Tech Name: REDACTED FOR PRIVACY\nTech Organization: REDACTED FOR PRIVACY\nTech Street: REDACTED FOR PRIVACY\nTech City: REDACTED FOR PRIVACY\nTech State\/Province: REDACTED FOR PRIVACY\nTech Postal Code: REDACTED FOR PRIVACY\nTech Country: REDACTED FOR PRIVACY\nTech Phone: REDACTED FOR PRIVACY\nTech Fax: REDACTED FOR PRIVACY\nTech Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name." - }, - "billingContact": { - "name": "REDACTED FOR PRIVACY", - "organization": "REDACTED FOR PRIVACY", - "street": "REDACTED FOR PRIVACY", - "city": "REDACTED FOR PRIVACY", - "state": "REDACTED FOR PRIVACY", - "postalCode": "REDACTED FOR PRIVACY", - "country": "REDACTED FOR PRIVACY", - "email": null, - "telephone": "", - "telephoneExt": null, - "fax": "", - "faxExt": null, - "rawText": "Billing Name: REDACTED FOR PRIVACY\nBilling Organization: REDACTED FOR PRIVACY\nBilling Street: REDACTED FOR PRIVACY\nBilling City: REDACTED FOR PRIVACY\nBilling State\/Province: REDACTED FOR PRIVACY\nBilling Postal Code: REDACTED FOR PRIVACY\nBilling Country: REDACTED FOR PRIVACY\nBilling Phone: REDACTED FOR PRIVACY\nBilling Fax: REDACTED FOR PRIVACY\nBilling Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name." - }, - "zoneContact": { - "name": null, - "organization": null, - "street": "", - "city": null, - "state": null, - "postalCode": null, - "country": null, - "email": null, - "telephone": null, - "telephoneExt": null, - "fax": null, - "faxExt": null, - "rawText": null - } - }, - { - "domainName": "coach.sex", - "domainType": "dropped", - "createdDateISO8601": "2018-08-01T20:47:08+00:00", - "updatedDateISO8601": "2020-08-15T19:12:26+00:00", - "expiresDateISO8601": "2021-08-01T20:47:08+00:00", - "createdDateRaw": "2018-08-01T20:47:08.447Z", - "updatedDateRaw": "2020-08-15T19:12:26.051Z", - "expiresDateRaw": "2021-08-01T20:47:08.447Z", - "audit": { - "createdDate": "2020-08-16T17:52:30+00:00", - "updatedDate": "2020-08-16T17:52:30+00:00" - }, - "nameServers": [ - "ns2.zenbox.pl", - "ns1.zenbox.pl" - ], - "whoisServer": "whois.instra.net", - "registrarName": "Instra Corporation Pty Ltd.", - "status": [ - "clientHold", - "clientTransferProhibited", - "autoRenewPeriod" - ], - "cleanText": "Domain Name: coach.sex\nRegistrar WHOIS Server: whois.instra.net\nRegistrar URL: www.instra.com\nUpdated Date: 2020-08-15T19:12:26.051Z\nCreation Date: 2018-08-01T20:47:08.447Z\nRegistry Expiry Date: 2021-08-01T20:47:08.447Z\nRegistrar: Instra Corporation Pty Ltd.\nRegistrar IANA ID: 1376\nRegistrar Abuse Contact Email: support@instra.com\nRegistrar Abuse Contact Phone: +61.397831800\nDomain Status: clientHold https:\/\/icann.org\/epp#clientHold\nDomain Status: clientTransferProhibited https:\/\/icann.org\/epp#clientTransferProhibited\nDomain Status: autoRenewPeriod https:\/\/icann.org\/epp#autoRenewPeriod\nRegistrant Name: REDACTED FOR PRIVACY\nRegistrant Street: REDACTED FOR PRIVACY\nRegistrant City: REDACTED FOR PRIVACY\nRegistrant State\/Province: mazowieckie\nRegistrant Postal Code: REDACTED FOR PRIVACY\nRegistrant Country: PL\nRegistrant Phone: REDACTED FOR PRIVACY\nRegistrant Fax: REDACTED FOR PRIVACY\nRegistrant Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.\nAdmin Name: REDACTED FOR PRIVACY\nAdmin Organization: REDACTED FOR PRIVACY\nAdmin Street: REDACTED FOR PRIVACY\nAdmin City: REDACTED FOR PRIVACY\nAdmin State\/Province: REDACTED FOR PRIVACY\nAdmin Postal Code: REDACTED FOR PRIVACY\nAdmin Country: REDACTED FOR PRIVACY\nAdmin Phone: REDACTED FOR PRIVACY\nAdmin Fax: REDACTED FOR PRIVACY\nAdmin Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.\nTech Name: REDACTED FOR PRIVACY\nTech Organization: REDACTED FOR PRIVACY\nTech Street: REDACTED FOR PRIVACY\nTech City: REDACTED FOR PRIVACY\nTech State\/Province: REDACTED FOR PRIVACY\nTech Postal Code: REDACTED FOR PRIVACY\nTech Country: REDACTED FOR PRIVACY\nTech Phone: REDACTED FOR PRIVACY\nTech Fax: REDACTED FOR PRIVACY\nTech Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.\nBilling Name: REDACTED FOR PRIVACY\nBilling Organization: REDACTED FOR PRIVACY\nBilling Street: REDACTED FOR PRIVACY\nBilling City: REDACTED FOR PRIVACY\nBilling State\/Province: REDACTED FOR PRIVACY\nBilling Postal Code: REDACTED FOR PRIVACY\nBilling Country: REDACTED FOR PRIVACY\nBilling Phone: REDACTED FOR PRIVACY\nBilling Fax: REDACTED FOR PRIVACY\nBilling Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.\nName Server: ns2.zenbox.pl\nName Server: ns1.zenbox.pl\n", - "rawText": "Domain Name: coach.sex\nRegistry Domain ID: D425500000050058539-AGRS\nRegistrar WHOIS Server: whois.instra.net\nRegistrar URL: www.instra.com\nUpdated Date: 2020-08-15T19:12:26.051Z\nCreation Date: 2018-08-01T20:47:08.447Z\nRegistry Expiry Date: 2021-08-01T20:47:08.447Z\nRegistrar: Instra Corporation Pty Ltd.\nRegistrar IANA ID: 1376\nRegistrar Abuse Contact Email: support@instra.com\nRegistrar Abuse Contact Phone: +61.397831800\nDomain Status: clientHold https:\/\/icann.org\/epp#clientHold\nDomain Status: clientTransferProhibited https:\/\/icann.org\/epp#clientTransferProhibited\nDomain Status: autoRenewPeriod https:\/\/icann.org\/epp#autoRenewPeriod\nRegistry Registrant ID: REDACTED FOR PRIVACY\nRegistrant Name: REDACTED FOR PRIVACY\nRegistrant Organization: \nRegistrant Street: REDACTED FOR PRIVACY\nRegistrant City: REDACTED FOR PRIVACY\nRegistrant State\/Province: mazowieckie\nRegistrant Postal Code: REDACTED FOR PRIVACY\nRegistrant Country: PL\nRegistrant Phone: REDACTED FOR PRIVACY\nRegistrant Fax: REDACTED FOR PRIVACY\nRegistrant Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.\nRegistry Admin ID: REDACTED FOR PRIVACY\nAdmin Name: REDACTED FOR PRIVACY\nAdmin Organization: REDACTED FOR PRIVACY\nAdmin Street: REDACTED FOR PRIVACY\nAdmin City: REDACTED FOR PRIVACY\nAdmin State\/Province: REDACTED FOR PRIVACY\nAdmin Postal Code: REDACTED FOR PRIVACY\nAdmin Country: REDACTED FOR PRIVACY\nAdmin Phone: REDACTED FOR PRIVACY\nAdmin Fax: REDACTED FOR PRIVACY\nAdmin Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.\nRegistry Tech ID: REDACTED FOR PRIVACY\nTech Name: REDACTED FOR PRIVACY\nTech Organization: REDACTED FOR PRIVACY\nTech Street: REDACTED FOR PRIVACY\nTech City: REDACTED FOR PRIVACY\nTech State\/Province: REDACTED FOR PRIVACY\nTech Postal Code: REDACTED FOR PRIVACY\nTech Country: REDACTED FOR PRIVACY\nTech Phone: REDACTED FOR PRIVACY\nTech Fax: REDACTED FOR PRIVACY\nTech Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.\nRegistry Billing ID: REDACTED FOR PRIVACY\nBilling Name: REDACTED FOR PRIVACY\nBilling Organization: REDACTED FOR PRIVACY\nBilling Street: REDACTED FOR PRIVACY\nBilling City: REDACTED FOR PRIVACY\nBilling State\/Province: REDACTED FOR PRIVACY\nBilling Postal Code: REDACTED FOR PRIVACY\nBilling Country: REDACTED FOR PRIVACY\nBilling Phone: REDACTED FOR PRIVACY\nBilling Fax: REDACTED FOR PRIVACY\nBilling Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.\nName Server: ns2.zenbox.pl\nName Server: ns1.zenbox.pl\nDNSSEC: unsigned\nURL of the ICANN RDDS Inaccuracy Complaint Form: https:\/\/www.icann.org\/wicf\/\n\n>>> Last update of WHOIS database: 2020-08-16T17:52:19.372Z <<<\n\nFor more information on domain status codes, please visit https:\/\/icann.org\/epp\n\nThe WHOIS information provided in this page has been redacted\nin compliance with ICANN's Temporary Specification for gTLD\nRegistration Data.\n\nThe data in this record is provided by Uniregistry for informational\npurposes only, and it does not guarantee its accuracy. Uniregistry is\nauthoritative for whois information in top-level domains it operates\nunder contract with the Internet Corporation for Assigned Names and\nNumbers. Whois information from other top-level domains is provided by\na third-party under license to Uniregistry.\n\nThis service is intended only for query-based access. By using this\nservice, you agree that you will use any data presented only for lawful\npurposes and that, under no circumstances will you use (a) data\nacquired for the purpose of allowing, enabling, or otherwise supporting\nthe transmission by e-mail, telephone, facsimile or other\ncommunications mechanism of mass unsolicited, commercial advertising\nor solicitations to entities other than your existing customers; or\n(b) this service to enable high volume, automated, electronic processes\nthat send queries or data to the systems of any Registrar or any\nRegistry except as reasonably necessary to register domain names or\nmodify existing domain name registrations.\n\nUniregistry reserves the right to modify these terms at any time. By\nsubmitting this query, you agree to abide by this policy. All rights\nreserved.", - "registrantContact": { - "name": "REDACTED FOR PRIVACY", - "organization": null, - "street": "REDACTED FOR PRIVACY", - "city": "REDACTED FOR PRIVACY", - "state": "mazowieckie", - "postalCode": "REDACTED FOR PRIVACY", - "country": "POLAND", - "email": null, - "telephone": "", - "telephoneExt": null, - "fax": "", - "faxExt": null, - "rawText": "Registrant Name: REDACTED FOR PRIVACY\nRegistrant Street: REDACTED FOR PRIVACY\nRegistrant City: REDACTED FOR PRIVACY\nRegistrant State\/Province: mazowieckie\nRegistrant Postal Code: REDACTED FOR PRIVACY\nRegistrant Country: PL\nRegistrant Phone: REDACTED FOR PRIVACY\nRegistrant Fax: REDACTED FOR PRIVACY\nRegistrant Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name." - }, - "administrativeContact": { - "name": "REDACTED FOR PRIVACY", - "organization": "REDACTED FOR PRIVACY", - "street": "REDACTED FOR PRIVACY", - "city": "REDACTED FOR PRIVACY", - "state": "REDACTED FOR PRIVACY", - "postalCode": "REDACTED FOR PRIVACY", - "country": "REDACTED FOR PRIVACY", - "email": null, - "telephone": "", - "telephoneExt": null, - "fax": "", - "faxExt": null, - "rawText": "Admin Name: REDACTED FOR PRIVACY\nAdmin Organization: REDACTED FOR PRIVACY\nAdmin Street: REDACTED FOR PRIVACY\nAdmin City: REDACTED FOR PRIVACY\nAdmin State\/Province: REDACTED FOR PRIVACY\nAdmin Postal Code: REDACTED FOR PRIVACY\nAdmin Country: REDACTED FOR PRIVACY\nAdmin Phone: REDACTED FOR PRIVACY\nAdmin Fax: REDACTED FOR PRIVACY\nAdmin Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name." - }, - "technicalContact": { - "name": "REDACTED FOR PRIVACY", - "organization": "REDACTED FOR PRIVACY", - "street": "REDACTED FOR PRIVACY", - "city": "REDACTED FOR PRIVACY", - "state": "REDACTED FOR PRIVACY", - "postalCode": "REDACTED FOR PRIVACY", - "country": "REDACTED FOR PRIVACY", - "email": null, - "telephone": "", - "telephoneExt": null, - "fax": "", - "faxExt": null, - "rawText": "Tech Name: REDACTED FOR PRIVACY\nTech Organization: REDACTED FOR PRIVACY\nTech Street: REDACTED FOR PRIVACY\nTech City: REDACTED FOR PRIVACY\nTech State\/Province: REDACTED FOR PRIVACY\nTech Postal Code: REDACTED FOR PRIVACY\nTech Country: REDACTED FOR PRIVACY\nTech Phone: REDACTED FOR PRIVACY\nTech Fax: REDACTED FOR PRIVACY\nTech Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name." - }, - "billingContact": { - "name": "REDACTED FOR PRIVACY", - "organization": "REDACTED FOR PRIVACY", - "street": "REDACTED FOR PRIVACY", - "city": "REDACTED FOR PRIVACY", - "state": "REDACTED FOR PRIVACY", - "postalCode": "REDACTED FOR PRIVACY", - "country": "REDACTED FOR PRIVACY", - "email": null, - "telephone": "", - "telephoneExt": null, - "fax": "", - "faxExt": null, - "rawText": "Billing Name: REDACTED FOR PRIVACY\nBilling Organization: REDACTED FOR PRIVACY\nBilling Street: REDACTED FOR PRIVACY\nBilling City: REDACTED FOR PRIVACY\nBilling State\/Province: REDACTED FOR PRIVACY\nBilling Postal Code: REDACTED FOR PRIVACY\nBilling Country: REDACTED FOR PRIVACY\nBilling Phone: REDACTED FOR PRIVACY\nBilling Fax: REDACTED FOR PRIVACY\nBilling Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name." - }, - "zoneContact": { - "name": null, - "organization": null, - "street": "", - "city": null, - "state": null, - "postalCode": null, - "country": null, - "email": null, - "telephone": null, - "telephoneExt": null, - "fax": null, - "faxExt": null, - "rawText": null - } - }, - { - "domainName": "coach.sex", - "domainType": "added", - "createdDateISO8601": "2018-08-01T20:47:08+00:00", - "updatedDateISO8601": "2019-10-29T19:13:20+00:00", - "expiresDateISO8601": "2020-08-01T20:47:08+00:00", - "createdDateRaw": "2018-08-01T20:47:08.447Z", - "updatedDateRaw": "2019-10-29T19:13:20.489Z", - "expiresDateRaw": "2020-08-01T20:47:08.447Z", - "audit": { - "createdDate": "2020-01-13T08:00:00+00:00", - "updatedDate": "2020-01-13T08:00:00+00:00" - }, - "nameServers": [ - "ns2.zenbox.pl", - "ns1.zenbox.pl" - ], - "whoisServer": "whois.instra.net", - "registrarName": "Instra Corporation Pty Ltd.", - "status": [ - "clientTransferProhibited" - ], - "cleanText": "Domain Name: coach.sex\nRegistry Domain ID: D425500000050058539-AGRS\nRegistrar WHOIS Server: whois.instra.net\nRegistrar URL: www.instra.com\nUpdated Date: 2019-10-29T19:13:20.489Z\nCreation Date: 2018-08-01T20:47:08.447Z\nRegistry Expiry Date: 2020-08-01T20:47:08.447Z\nRegistrar: Instra Corporation Pty Ltd.\nRegistrar IANA ID: 1376\nRegistrar Abuse Contact Email: support@instra.com\nRegistrar Abuse Contact Phone: +61.397831800\nDomain Status: clientTransferProhibited https:\/\/icann.org\/epp#clientTransferProhibited\nRegistry Registrant ID: REDACTED FOR PRIVACY\nRegistrant Name: REDACTED FOR PRIVACY\nRegistrant Organization: \nRegistrant Street: REDACTED FOR PRIVACY\nRegistrant City: REDACTED FOR PRIVACY\nRegistrant State\/Province: podkarpackie\nRegistrant Postal Code: REDACTED FOR PRIVACY\nRegistrant Country: PL\nRegistrant Phone: REDACTED FOR PRIVACY\nRegistrant Fax: REDACTED FOR PRIVACY\nRegistrant Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.\nRegistry Admin ID: REDACTED FOR PRIVACY\nAdmin Name: REDACTED FOR PRIVACY\nAdmin Organization: REDACTED FOR PRIVACY\nAdmin Street: REDACTED FOR PRIVACY\nAdmin City: REDACTED FOR PRIVACY\nAdmin State\/Province: REDACTED FOR PRIVACY\nAdmin Postal Code: REDACTED FOR PRIVACY\nAdmin Country: REDACTED FOR PRIVACY\nAdmin Phone: REDACTED FOR PRIVACY\nAdmin Fax: REDACTED FOR PRIVACY\nAdmin Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.\nRegistry Tech ID: REDACTED FOR PRIVACY\nTech Name: REDACTED FOR PRIVACY\nTech Organization: REDACTED FOR PRIVACY\nTech Street: REDACTED FOR PRIVACY\nTech City: REDACTED FOR PRIVACY\nTech State\/Province: REDACTED FOR PRIVACY\nTech Postal Code: REDACTED FOR PRIVACY\nTech Country: REDACTED FOR PRIVACY\nTech Phone: REDACTED FOR PRIVACY\nTech Fax: REDACTED FOR PRIVACY\nTech Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.\nRegistry Billing ID: REDACTED FOR PRIVACY\nBilling Name: REDACTED FOR PRIVACY\nBilling Organization: REDACTED FOR PRIVACY\nBilling Street: REDACTED FOR PRIVACY\nBilling City: REDACTED FOR PRIVACY\nBilling State\/Province: REDACTED FOR PRIVACY\nBilling Postal Code: REDACTED FOR PRIVACY\nBilling Country: REDACTED FOR PRIVACY\nBilling Phone: REDACTED FOR PRIVACY\nBilling Fax: REDACTED FOR PRIVACY\nBilling Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.\nName Server: ns2.zenbox.pl\nName Server: ns1.zenbox.pl\nDNSSEC: unsigned\nURL of the ICANN RDDS Inaccuracy Complaint Form: https:\/\/www.icann.org\/wicf\/\n\n>>> Last update of WHOIS database: 2020-01-13T01:43:21.865Z <<<\n\nFor more information on domain status codes, please visit https:\/\/icann.org\/epp\n\nThe WHOIS information provided in this page has been redacted\nin compliance with ICANN's Temporary Specification for gTLD\nRegistration Data.\n\nThe data in this record is provided by Uniregistry for informational\npurposes only, and it does not guarantee its accuracy. Uniregistry is\nauthoritative for whois information in top-level domains it operates\nunder contract with the Internet Corporation for Assigned Names and\nNumbers. Whois information from other top-level domains is provided by\na third-party under license to Uniregistry.\n\nThis service is intended only for query-based access. By using this\nservice, you agree that you will use any data presented only for lawful\npurposes and that, under no circumstances will you use (a) data\nacquired for the purpose of allowing, enabling, or otherwise supporting\nthe transmission by e-mail, telephone, facsimile or other\ncommunications mechanism of mass unsolicited, commercial advertising\nor solicitations to entities other than your existing customers; or\n(b) this service to enable high volume, automated, electronic processes\nthat send queries or data to the systems of any Registrar or any\nRegistry except as reasonably necessary to register domain names or\nmodify existing domain name registrations.\n\nUniregistry reserves the right to modify these terms at any time. By\nsubmitting this query, you agree to abide by this policy. All rights\nreserved.", - "rawText": "Domain Name: coach.sex\nRegistry Domain ID: D425500000050058539-AGRS\nRegistrar WHOIS Server: whois.instra.net\nRegistrar URL: www.instra.com\nUpdated Date: 2019-10-29T19:13:20.489Z\nCreation Date: 2018-08-01T20:47:08.447Z\nRegistry Expiry Date: 2020-08-01T20:47:08.447Z\nRegistrar: Instra Corporation Pty Ltd.\nRegistrar IANA ID: 1376\nRegistrar Abuse Contact Email: support@instra.com\nRegistrar Abuse Contact Phone: +61.397831800\nDomain Status: clientTransferProhibited https:\/\/icann.org\/epp#clientTransferProhibited\nRegistry Registrant ID: REDACTED FOR PRIVACY\nRegistrant Name: REDACTED FOR PRIVACY\nRegistrant Organization: \nRegistrant Street: REDACTED FOR PRIVACY\nRegistrant City: REDACTED FOR PRIVACY\nRegistrant State\/Province: podkarpackie\nRegistrant Postal Code: REDACTED FOR PRIVACY\nRegistrant Country: PL\nRegistrant Phone: REDACTED FOR PRIVACY\nRegistrant Fax: REDACTED FOR PRIVACY\nRegistrant Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.\nRegistry Admin ID: REDACTED FOR PRIVACY\nAdmin Name: REDACTED FOR PRIVACY\nAdmin Organization: REDACTED FOR PRIVACY\nAdmin Street: REDACTED FOR PRIVACY\nAdmin City: REDACTED FOR PRIVACY\nAdmin State\/Province: REDACTED FOR PRIVACY\nAdmin Postal Code: REDACTED FOR PRIVACY\nAdmin Country: REDACTED FOR PRIVACY\nAdmin Phone: REDACTED FOR PRIVACY\nAdmin Fax: REDACTED FOR PRIVACY\nAdmin Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.\nRegistry Tech ID: REDACTED FOR PRIVACY\nTech Name: REDACTED FOR PRIVACY\nTech Organization: REDACTED FOR PRIVACY\nTech Street: REDACTED FOR PRIVACY\nTech City: REDACTED FOR PRIVACY\nTech State\/Province: REDACTED FOR PRIVACY\nTech Postal Code: REDACTED FOR PRIVACY\nTech Country: REDACTED FOR PRIVACY\nTech Phone: REDACTED FOR PRIVACY\nTech Fax: REDACTED FOR PRIVACY\nTech Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.\nRegistry Billing ID: REDACTED FOR PRIVACY\nBilling Name: REDACTED FOR PRIVACY\nBilling Organization: REDACTED FOR PRIVACY\nBilling Street: REDACTED FOR PRIVACY\nBilling City: REDACTED FOR PRIVACY\nBilling State\/Province: REDACTED FOR PRIVACY\nBilling Postal Code: REDACTED FOR PRIVACY\nBilling Country: REDACTED FOR PRIVACY\nBilling Phone: REDACTED FOR PRIVACY\nBilling Fax: REDACTED FOR PRIVACY\nBilling Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.\nName Server: ns2.zenbox.pl\nName Server: ns1.zenbox.pl\nDNSSEC: unsigned\nURL of the ICANN RDDS Inaccuracy Complaint Form: https:\/\/www.icann.org\/wicf\/\n\n>>> Last update of WHOIS database: 2020-01-13T01:43:21.865Z <<<\n\nFor more information on domain status codes, please visit https:\/\/icann.org\/epp\n\nThe WHOIS information provided in this page has been redacted\nin compliance with ICANN's Temporary Specification for gTLD\nRegistration Data.\n\nThe data in this record is provided by Uniregistry for informational\npurposes only, and it does not guarantee its accuracy. Uniregistry is\nauthoritative for whois information in top-level domains it operates\nunder contract with the Internet Corporation for Assigned Names and\nNumbers. Whois information from other top-level domains is provided by\na third-party under license to Uniregistry.\n\nThis service is intended only for query-based access. By using this\nservice, you agree that you will use any data presented only for lawful\npurposes and that, under no circumstances will you use (a) data\nacquired for the purpose of allowing, enabling, or otherwise supporting\nthe transmission by e-mail, telephone, facsimile or other\ncommunications mechanism of mass unsolicited, commercial advertising\nor solicitations to entities other than your existing customers; or\n(b) this service to enable high volume, automated, electronic processes\nthat send queries or data to the systems of any Registrar or any\nRegistry except as reasonably necessary to register domain names or\nmodify existing domain name registrations.\n\nUniregistry reserves the right to modify these terms at any time. By\nsubmitting this query, you agree to abide by this policy. All rights\nreserved.", - "registrantContact": { - "name": "REDACTED FOR PRIVACY", - "organization": null, - "street": "REDACTED FOR PRIVACY", - "city": "REDACTED FOR PRIVACY", - "state": "podkarpackie", - "postalCode": "REDACTED FOR PRIVACY", - "country": "POLAND", - "email": null, - "telephone": null, - "telephoneExt": null, - "fax": null, - "faxExt": null, - "rawText": "Registrant Name: REDACTED FOR PRIVACY|Registrant Street: REDACTED FOR PRIVACY|Registrant City: REDACTED FOR PRIVACY|Registrant State\/Province: podkarpackie|Registrant Postal Code: REDACTED FOR PRIVACY|Registrant Country: PL|Registrant Phone: REDACTED FOR PRIVACY|Registrant Fax: REDACTED FOR PRIVACY|Registrant Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name." - }, - "administrativeContact": { - "name": "REDACTED FOR PRIVACY", - "organization": "REDACTED FOR PRIVACY", - "street": "REDACTED FOR PRIVACY", - "city": "REDACTED FOR PRIVACY", - "state": "REDACTED FOR PRIVACY", - "postalCode": "REDACTED FOR PRIVACY", - "country": "REDACTED FOR PRIVACY", - "email": null, - "telephone": null, - "telephoneExt": null, - "fax": null, - "faxExt": null, - "rawText": "Admin Name: REDACTED FOR PRIVACY|Admin Organization: REDACTED FOR PRIVACY|Admin Street: REDACTED FOR PRIVACY|Admin City: REDACTED FOR PRIVACY|Admin State\/Province: REDACTED FOR PRIVACY|Admin Postal Code: REDACTED FOR PRIVACY|Admin Country: REDACTED FOR PRIVACY|Admin Phone: REDACTED FOR PRIVACY|Admin Fax: REDACTED FOR PRIVACY|Admin Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name." - }, - "technicalContact": { - "name": "REDACTED FOR PRIVACY", - "organization": "REDACTED FOR PRIVACY", - "street": "REDACTED FOR PRIVACY", - "city": "REDACTED FOR PRIVACY", - "state": "REDACTED FOR PRIVACY", - "postalCode": "REDACTED FOR PRIVACY", - "country": "REDACTED FOR PRIVACY", - "email": null, - "telephone": null, - "telephoneExt": null, - "fax": null, - "faxExt": null, - "rawText": "Tech Name: REDACTED FOR PRIVACY|Tech Organization: REDACTED FOR PRIVACY|Tech Street: REDACTED FOR PRIVACY|Tech City: REDACTED FOR PRIVACY|Tech State\/Province: REDACTED FOR PRIVACY|Tech Postal Code: REDACTED FOR PRIVACY|Tech Country: REDACTED FOR PRIVACY|Tech Phone: REDACTED FOR PRIVACY|Tech Fax: REDACTED FOR PRIVACY|Tech Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name." - }, - "billingContact": { - "name": "REDACTED FOR PRIVACY", - "organization": "REDACTED FOR PRIVACY", - "street": "REDACTED FOR PRIVACY", - "city": "REDACTED FOR PRIVACY", - "state": "REDACTED FOR PRIVACY", - "postalCode": "REDACTED FOR PRIVACY", - "country": "REDACTED FOR PRIVACY", - "email": null, - "telephone": null, - "telephoneExt": null, - "fax": null, - "faxExt": null, - "rawText": "Billing Name: REDACTED FOR PRIVACY|Billing Organization: REDACTED FOR PRIVACY|Billing Street: REDACTED FOR PRIVACY|Billing City: REDACTED FOR PRIVACY|Billing State\/Province: REDACTED FOR PRIVACY|Billing Postal Code: REDACTED FOR PRIVACY|Billing Country: REDACTED FOR PRIVACY|Billing Phone: REDACTED FOR PRIVACY|Billing Fax: REDACTED FOR PRIVACY|Billing Email: Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name." - }, - "zoneContact": { - "name": null, - "organization": null, - "street": "", - "city": null, - "state": null, - "postalCode": null, - "country": null, - "email": null, - "telephone": null, - "telephoneExt": null, - "fax": null, - "faxExt": null, - "rawText": null - } - }, - { - "domainName": "coach.sex", - "domainType": "added", - "createdDateISO8601": "2018-08-01T20:47:08+00:00", - "updatedDateISO8601": "2019-08-26T16:32:41+00:00", - "expiresDateISO8601": "2020-08-01T20:47:08+00:00", - "createdDateRaw": "2018-08-01T20:47:08Z", - "updatedDateRaw": "2019-08-26T16:32:41Z", - "expiresDateRaw": "2020-08-01T20:47:08Z", - "audit": { - "createdDate": "2019-08-27T16:38:18+00:00", - "updatedDate": "2019-08-27T16:38:18+00:00" - }, - "nameServers": [ - "NS1.ZENBOX.PL", - "NS2.ZENBOX.PL" - ], - "whoisServer": "whois.nic.sex", - "registrarName": "Instra Corporation Pty Ltd.", - "status": [ - "clientTransferProhibited", - "autoRenewPeriod" - ], - "cleanText": "Domain Name: COACH.SEX\nRegistry Domain ID: D425500000050058539-AGRS\nRegistrar WHOIS Server:\nRegistrar URL: http:\/\/www.instra.com\nUpdated Date: 2019-08-26T16:32:41Z\nCreation Date: 2018-08-01T20:47:08Z\nRegistry Expiry Date: 2020-08-01T20:47:08Z\nRegistrar Registration Expiration Date:\nRegistrar: Instra Corporation Pty Ltd.\nRegistrar IANA ID: 1376\nRegistrar Abuse Contact Email: abuse@instra.com\nRegistrar Abuse Contact Phone:\nReseller:\nDomain Status: clientTransferProhibited https:\/\/icann.org\/epp#clientTransferProhibited\nDomain Status: autoRenewPeriod https:\/\/icann.org\/epp#autoRenewPeriod\nRegistrant Organization:\nRegistrant State\/Province: podkarpackie\nRegistrant Country: PL\nName Server: NS1.ZENBOX.PL\nName Server: NS2.ZENBOX.PL\nDNSSEC: unsigned\nURL of the ICANN Whois Inaccuracy Complaint Form https:\/\/www.icann.org\/wicf\/)\n>>> Last update of WHOIS database: 2019-08-27T16:37:08Z <<<\nFor more information on Whois status codes, please visit https:\/\/icann.org\/epp\nAccess to WHOIS information is provided to assist persons in determining the contents of a domain name registration record in the registry database. The data in this record is provided by The Registry Operator for informational purposes only, and accuracy is not guaranteed. This service is intended only for query-based access. You agree that you will use this data only for lawful purposes and that, under no circumstances will you use this data to (a) allow, enable, or otherwise support the transmission by e-mail, telephone, or facsimile of mass unsolicited, commercial advertising or solicitations to entities other than the data recipient's own existing customers; or (b) enable high volume, automated, electronic processes that send queries or data to the systems of Registry Operator, a Registrar, or Afilias except as reasonably necessary to register domain names or modify existing registrations. All rights reserved. Registry Operator reserves the right to modify these terms at any time. By submitting this query, you agree to abide by this policy.\nThe Registrar of Record identified in this output may have an RDDS service that can be queried for additional information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.\n", - "rawText": "Domain Name: COACH.SEX\nRegistry Domain ID: D425500000050058539-AGRS\nRegistrar WHOIS Server:\nRegistrar URL: http:\/\/www.instra.com\nUpdated Date: 2019-08-26T16:32:41Z\nCreation Date: 2018-08-01T20:47:08Z\nRegistry Expiry Date: 2020-08-01T20:47:08Z\nRegistrar Registration Expiration Date:\nRegistrar: Instra Corporation Pty Ltd.\nRegistrar IANA ID: 1376\nRegistrar Abuse Contact Email: abuse@instra.com\nRegistrar Abuse Contact Phone:\nReseller:\nDomain Status: clientTransferProhibited https:\/\/icann.org\/epp#clientTransferProhibited\nDomain Status: autoRenewPeriod https:\/\/icann.org\/epp#autoRenewPeriod\nRegistrant Organization:\nRegistrant State\/Province: podkarpackie\nRegistrant Country: PL\nName Server: NS1.ZENBOX.PL\nName Server: NS2.ZENBOX.PL\nDNSSEC: unsigned\nURL of the ICANN Whois Inaccuracy Complaint Form https:\/\/www.icann.org\/wicf\/)\n>>> Last update of WHOIS database: 2019-08-27T16:37:08Z <<<\n\nFor more information on Whois status codes, please visit https:\/\/icann.org\/epp\n\nAccess to WHOIS information is provided to assist persons in determining the contents of a domain name registration record in the registry database. The data in this record is provided by The Registry Operator for informational purposes only, and accuracy is not guaranteed. This service is intended only for query-based access. You agree that you will use this data only for lawful purposes and that, under no circumstances will you use this data to (a) allow, enable, or otherwise support the transmission by e-mail, telephone, or facsimile of mass unsolicited, commercial advertising or solicitations to entities other than the data recipient's own existing customers; or (b) enable high volume, automated, electronic processes that send queries or data to the systems of Registry Operator, a Registrar, or Afilias except as reasonably necessary to register domain names or modify existing registrations. All rights reserved. Registry Operator reserves the right to modify these terms at any time. By submitting this query, you agree to abide by this policy.\n\nThe Registrar of Record identified in this output may have an RDDS service that can be queried for additional information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.", - "registrantContact": { - "name": "Registrant Country: PL", - "organization": "", - "street": "Registrant Country: PL", - "city": "", - "state": "podkarpackie", - "postalCode": "", - "country": "POLAND", - "email": "", - "telephone": "", - "telephoneExt": "", - "fax": "", - "faxExt": "", - "rawText": "Registrant Country: PL" - }, - "administrativeContact": { - "name": "", - "organization": "", - "street": "", - "city": "", - "state": "", - "postalCode": "", - "country": "", - "email": "", - "telephone": "", - "telephoneExt": "", - "fax": "", - "faxExt": "", - "rawText": "" - }, - "technicalContact": { - "name": "", - "organization": "", - "street": "", - "city": "", - "state": "", - "postalCode": "", - "country": "", - "email": "", - "telephone": "", - "telephoneExt": "", - "fax": "", - "faxExt": "", - "rawText": "" - }, - "billingContact": { - "name": "", - "organization": "", - "street": "", - "city": "", - "state": "", - "postalCode": "", - "country": "", - "email": "", - "telephone": "", - "telephoneExt": "", - "fax": "", - "faxExt": "", - "rawText": "" - }, - "zoneContact": { - "name": "", - "organization": "", - "street": "", - "city": "", - "state": "", - "postalCode": "", - "country": "", - "email": "", - "telephone": "", - "telephoneExt": "", - "fax": "", - "faxExt": "", - "rawText": "" - } - }, - { - "domainName": "coach.sex", - "domainType": "dropped", - "createdDateISO8601": "2018-08-01T20:47:08+00:00", - "updatedDateISO8601": "2019-08-15T19:13:27+00:00", - "expiresDateISO8601": "2020-08-01T20:47:08+00:00", - "createdDateRaw": "2018-08-01T20:47:08Z", - "updatedDateRaw": "2019-08-15T19:13:27Z", - "expiresDateRaw": "2020-08-01T20:47:08Z", - "audit": { - "createdDate": "2019-08-16T16:52:48+00:00", - "updatedDate": "2019-08-16T16:52:48+00:00" - }, - "nameServers": [ - "NS1.ZENBOX.PL", - "NS2.ZENBOX.PL" - ], - "whoisServer": "whois.nic.sex", - "registrarName": "Instra Corporation Pty Ltd.", - "status": [ - "clientHold", - "clientTransferProhibited", - "autoRenewPeriod" - ], - "cleanText": "Domain Name: COACH.SEX\nRegistry Domain ID: D425500000050058539-AGRS\nRegistrar WHOIS Server:\nRegistrar URL: http:\/\/www.instra.com\nUpdated Date: 2019-08-15T19:13:27Z\nCreation Date: 2018-08-01T20:47:08Z\nRegistry Expiry Date: 2020-08-01T20:47:08Z\nRegistrar Registration Expiration Date:\nRegistrar: Instra Corporation Pty Ltd.\nRegistrar IANA ID: 1376\nRegistrar Abuse Contact Email: abuse@instra.com\nRegistrar Abuse Contact Phone:\nReseller:\nDomain Status: clientHold https:\/\/icann.org\/epp#clientHold\nDomain Status: clientTransferProhibited https:\/\/icann.org\/epp#clientTransferProhibited\nDomain Status: autoRenewPeriod https:\/\/icann.org\/epp#autoRenewPeriod\nRegistrant Organization:\nRegistrant State\/Province: podkarpackie\nRegistrant Country: PL\nName Server: NS1.ZENBOX.PL\nName Server: NS2.ZENBOX.PL\nDNSSEC: unsigned\nURL of the ICANN Whois Inaccuracy Complaint Form https:\/\/www.icann.org\/wicf\/)\n>>> Last update of WHOIS database: 2019-08-16T16:51:47Z <<<\nFor more information on Whois status codes, please visit https:\/\/icann.org\/epp\nAccess to WHOIS information is provided to assist persons in determining the contents of a domain name registration record in the registry database. The data in this record is provided by The Registry Operator for informational purposes only, and accuracy is not guaranteed. This service is intended only for query-based access. You agree that you will use this data only for lawful purposes and that, under no circumstances will you use this data to (a) allow, enable, or otherwise support the transmission by e-mail, telephone, or facsimile of mass unsolicited, commercial advertising or solicitations to entities other than the data recipient's own existing customers; or (b) enable high volume, automated, electronic processes that send queries or data to the systems of Registry Operator, a Registrar, or Afilias except as reasonably necessary to register domain names or modify existing registrations. All rights reserved. Registry Operator reserves the right to modify these terms at any time. By submitting this query, you agree to abide by this policy.\nThe Registrar of Record identified in this output may have an RDDS service that can be queried for additional information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.\n", - "rawText": "Domain Name: COACH.SEX\nRegistry Domain ID: D425500000050058539-AGRS\nRegistrar WHOIS Server:\nRegistrar URL: http:\/\/www.instra.com\nUpdated Date: 2019-08-15T19:13:27Z\nCreation Date: 2018-08-01T20:47:08Z\nRegistry Expiry Date: 2020-08-01T20:47:08Z\nRegistrar Registration Expiration Date:\nRegistrar: Instra Corporation Pty Ltd.\nRegistrar IANA ID: 1376\nRegistrar Abuse Contact Email: abuse@instra.com\nRegistrar Abuse Contact Phone:\nReseller:\nDomain Status: clientHold https:\/\/icann.org\/epp#clientHold\nDomain Status: clientTransferProhibited https:\/\/icann.org\/epp#clientTransferProhibited\nDomain Status: autoRenewPeriod https:\/\/icann.org\/epp#autoRenewPeriod\nRegistrant Organization:\nRegistrant State\/Province: podkarpackie\nRegistrant Country: PL\nName Server: NS1.ZENBOX.PL\nName Server: NS2.ZENBOX.PL\nDNSSEC: unsigned\nURL of the ICANN Whois Inaccuracy Complaint Form https:\/\/www.icann.org\/wicf\/)\n>>> Last update of WHOIS database: 2019-08-16T16:51:47Z <<<\n\nFor more information on Whois status codes, please visit https:\/\/icann.org\/epp\n\nAccess to WHOIS information is provided to assist persons in determining the contents of a domain name registration record in the registry database. The data in this record is provided by The Registry Operator for informational purposes only, and accuracy is not guaranteed. This service is intended only for query-based access. You agree that you will use this data only for lawful purposes and that, under no circumstances will you use this data to (a) allow, enable, or otherwise support the transmission by e-mail, telephone, or facsimile of mass unsolicited, commercial advertising or solicitations to entities other than the data recipient's own existing customers; or (b) enable high volume, automated, electronic processes that send queries or data to the systems of Registry Operator, a Registrar, or Afilias except as reasonably necessary to register domain names or modify existing registrations. All rights reserved. Registry Operator reserves the right to modify these terms at any time. By submitting this query, you agree to abide by this policy.\n\nThe Registrar of Record identified in this output may have an RDDS service that can be queried for additional information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.", - "registrantContact": { - "name": "Registrant Country: PL", - "organization": "", - "street": "Registrant Country: PL", - "city": "", - "state": "podkarpackie", - "postalCode": "", - "country": "POLAND", - "email": "", - "telephone": "", - "telephoneExt": "", - "fax": "", - "faxExt": "", - "rawText": "Registrant Country: PL" - }, - "administrativeContact": { - "name": "", - "organization": "", - "street": "", - "city": "", - "state": "", - "postalCode": "", - "country": "", - "email": "", - "telephone": "", - "telephoneExt": "", - "fax": "", - "faxExt": "", - "rawText": "" - }, - "technicalContact": { - "name": "", - "organization": "", - "street": "", - "city": "", - "state": "", - "postalCode": "", - "country": "", - "email": "", - "telephone": "", - "telephoneExt": "", - "fax": "", - "faxExt": "", - "rawText": "" - }, - "billingContact": { - "name": "", - "organization": "", - "street": "", - "city": "", - "state": "", - "postalCode": "", - "country": "", - "email": "", - "telephone": "", - "telephoneExt": "", - "fax": "", - "faxExt": "", - "rawText": "" - }, - "zoneContact": { - "name": "", - "organization": "", - "street": "", - "city": "", - "state": "", - "postalCode": "", - "country": "", - "email": "", - "telephone": "", - "telephoneExt": "", - "fax": "", - "faxExt": "", - "rawText": "" - } - }, - { - "domainName": "coach.sex", - "domainType": "added", - "createdDateISO8601": "2018-08-01T20:47:08+00:00", - "updatedDateISO8601": "2018-09-30T21:15:46+00:00", - "expiresDateISO8601": "2019-08-01T20:47:08+00:00", - "createdDateRaw": "2018-08-01T20:47:08Z", - "updatedDateRaw": "2018-09-30T21:15:46Z", - "expiresDateRaw": "2019-08-01T20:47:08Z", - "audit": { - "createdDate": "2018-10-07T07:00:00+00:00", - "updatedDate": "2018-10-07T07:00:00+00:00" - }, - "nameServers": [ - "NS1.ZENBOX.PL", - "NS2.ZENBOX.PL" - ], - "whoisServer": null, - "registrarName": "Instra Corporation Pty Ltd.", - "status": [ - "ok" - ], - "cleanText": "Domain Name: COACH.SEX\nRegistry Domain ID: D425500000050058539-AGRS\nRegistrar WHOIS Server:\nRegistrar URL: http:\/\/www.instra.com\nUpdated Date: 2018-09-30T21:15:46Z\nCreation Date: 2018-08-01T20:47:08Z\nRegistry Expiry Date: 2019-08-01T20:47:08Z\nRegistrar Registration Expiration Date:\nRegistrar: Instra Corporation Pty Ltd.\nRegistrar IANA ID: 1376\nRegistrar Abuse Contact Email:\nRegistrar Abuse Contact Phone:\nReseller:\nDomain Status: ok https:\/\/icann.org\/epp#ok\nRegistrant Organization:\nRegistrant State\/Province: podkarpackie\nRegistrant Country: PL\nName Server: NS1.ZENBOX.PL\nName Server: NS2.ZENBOX.PL\nDNSSEC: unsigned\nURL of the ICANN Whois Inaccuracy Complaint Form https:\/\/www.icann.org\/wicf\/)\n>>> Last update of WHOIS database: 2018-10-07T14:46:15Z <<<\n\nFor more information on Whois status codes, please visit https:\/\/icann.org\/epp\n\nAccess to WHOIS information is provided to assist persons in determining the contents of a domain name registration record in the registry database. The data in this record is provided by The Registry Operator for informational purposes only, and accuracy is not guaranteed. This service is intended only for query-based access. You agree that you will use this data only for lawful purposes and that, under no circumstances will you use this data to (a) allow, enable, or otherwise support the transmission by e-mail, telephone, or facsimile of mass unsolicited, commercial advertising or solicitations to entities other than the data recipient's own existing customers; or (b) enable high volume, automated, electronic processes that send queries or data to the systems of Registry Operator, a Registrar, or Afilias except as reasonably necessary to register domain names or modify existing registrations. All rights reserved. Registry Operator reserves the right to modify these terms at any time. By submitting this query, you agree to abide by this policy.\n\nThe Registrar of Record identified in this output may have an RDDS service that can be queried for additional information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.", - "rawText": "Domain Name: COACH.SEX\nRegistry Domain ID: D425500000050058539-AGRS\nRegistrar WHOIS Server:\nRegistrar URL: http:\/\/www.instra.com\nUpdated Date: 2018-09-30T21:15:46Z\nCreation Date: 2018-08-01T20:47:08Z\nRegistry Expiry Date: 2019-08-01T20:47:08Z\nRegistrar Registration Expiration Date:\nRegistrar: Instra Corporation Pty Ltd.\nRegistrar IANA ID: 1376\nRegistrar Abuse Contact Email:\nRegistrar Abuse Contact Phone:\nReseller:\nDomain Status: ok https:\/\/icann.org\/epp#ok\nRegistrant Organization:\nRegistrant State\/Province: podkarpackie\nRegistrant Country: PL\nName Server: NS1.ZENBOX.PL\nName Server: NS2.ZENBOX.PL\nDNSSEC: unsigned\nURL of the ICANN Whois Inaccuracy Complaint Form https:\/\/www.icann.org\/wicf\/)\n>>> Last update of WHOIS database: 2018-10-07T14:46:15Z <<<\n\nFor more information on Whois status codes, please visit https:\/\/icann.org\/epp\n\nAccess to WHOIS information is provided to assist persons in determining the contents of a domain name registration record in the registry database. The data in this record is provided by The Registry Operator for informational purposes only, and accuracy is not guaranteed. This service is intended only for query-based access. You agree that you will use this data only for lawful purposes and that, under no circumstances will you use this data to (a) allow, enable, or otherwise support the transmission by e-mail, telephone, or facsimile of mass unsolicited, commercial advertising or solicitations to entities other than the data recipient's own existing customers; or (b) enable high volume, automated, electronic processes that send queries or data to the systems of Registry Operator, a Registrar, or Afilias except as reasonably necessary to register domain names or modify existing registrations. All rights reserved. Registry Operator reserves the right to modify these terms at any time. By submitting this query, you agree to abide by this policy.\n\nThe Registrar of Record identified in this output may have an RDDS service that can be queried for additional information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.", - "registrantContact": { - "name": "Registrant Country: PL", - "organization": null, - "street": "Registrant Country: PL", - "city": null, - "state": "podkarpackie", - "postalCode": null, - "country": "POLAND", - "email": null, - "telephone": null, - "telephoneExt": null, - "fax": null, - "faxExt": null, - "rawText": "Registrant Country: PL" - }, - "administrativeContact": { - "name": null, - "organization": null, - "street": "", - "city": null, - "state": null, - "postalCode": null, - "country": null, - "email": null, - "telephone": null, - "telephoneExt": null, - "fax": null, - "faxExt": null, - "rawText": null - }, - "technicalContact": { - "name": null, - "organization": null, - "street": "", - "city": null, - "state": null, - "postalCode": null, - "country": null, - "email": null, - "telephone": null, - "telephoneExt": null, - "fax": null, - "faxExt": null, - "rawText": null - }, - "billingContact": { - "name": null, - "organization": null, - "street": "", - "city": null, - "state": null, - "postalCode": null, - "country": null, - "email": null, - "telephone": null, - "telephoneExt": null, - "fax": null, - "faxExt": null, - "rawText": null - }, - "zoneContact": { - "name": null, - "organization": null, - "street": "", - "city": null, - "state": null, - "postalCode": null, - "country": null, - "email": null, - "telephone": null, - "telephoneExt": null, - "fax": null, - "faxExt": null, - "rawText": null - } - }, - { - "domainName": "coach.sex", - "domainType": "added", - "createdDateISO8601": "2018-08-01T20:47:08+00:00", - "updatedDateISO8601": "2018-09-14T18:17:08+00:00", - "expiresDateISO8601": "2019-08-01T20:47:08+00:00", - "createdDateRaw": "2018-08-01T20:47:08Z", - "updatedDateRaw": "2018-09-14T18:17:08Z", - "expiresDateRaw": "2019-08-01T20:47:08Z", - "audit": { - "createdDate": "2018-09-15T19:18:37+00:00", - "updatedDate": "2018-09-15T19:18:37+00:00" - }, - "nameServers": [ - "NS1.ZENBOX.PL", - "NS2.ZENBOX.PL" - ], - "whoisServer": "whois.nic.sex", - "registrarName": "Instra Corporation Pty Ltd.", - "status": [ - "serverTransferProhibited" - ], - "cleanText": "Domain Name: COACH.SEX\nRegistry Domain ID: D425500000050058539-AGRS\nRegistrar WHOIS Server:\nRegistrar URL: http:\/\/www.instra.com\nUpdated Date: 2018-09-14T18:17:08Z\nCreation Date: 2018-08-01T20:47:08Z\nRegistry Expiry Date: 2019-08-01T20:47:08Z\nRegistrar Registration Expiration Date:\nRegistrar: Instra Corporation Pty Ltd.\nRegistrar IANA ID: 1376\nRegistrar Abuse Contact Email:\nRegistrar Abuse Contact Phone:\nReseller:\nDomain Status: serverTransferProhibited https:\/\/icann.org\/epp#serverTransferProhibited\nRegistrant Organization:\nRegistrant State\/Province: podkarpackie\nRegistrant Country: PL\nName Server: NS1.ZENBOX.PL\nName Server: NS2.ZENBOX.PL\nDNSSEC: unsigned\nURL of the ICANN Whois Inaccuracy Complaint Form https:\/\/www.icann.org\/wicf\/)\n>>> Last update of WHOIS database: 2018-09-15T19:17:34Z <<<\nFor more information on Whois status codes, please visit https:\/\/icann.org\/epp\nAccess to WHOIS information is provided to assist persons in determining the contents of a domain name registration record in the registry database. The data in this record is provided by The Registry Operator for informational purposes only, and accuracy is not guaranteed. This service is intended only for query-based access. You agree that you will use this data only for lawful purposes and that, under no circumstances will you use this data to (a) allow, enable, or otherwise support the transmission by e-mail, telephone, or facsimile of mass unsolicited, commercial advertising or solicitations to entities other than the data recipient's own existing customers; or (b) enable high volume, automated, electronic processes that send queries or data to the systems of Registry Operator, a Registrar, or Afilias except as reasonably necessary to register domain names or modify existing registrations. All rights reserved. Registry Operator reserves the right to modify these terms at any time. By submitting this query, you agree to abide by this policy.\nThe Registrar of Record identified in this output may have an RDDS service that can be queried for additional information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.\n", - "rawText": "Domain Name: COACH.SEX\nRegistry Domain ID: D425500000050058539-AGRS\nRegistrar WHOIS Server:\nRegistrar URL: http:\/\/www.instra.com\nUpdated Date: 2018-09-14T18:17:08Z\nCreation Date: 2018-08-01T20:47:08Z\nRegistry Expiry Date: 2019-08-01T20:47:08Z\nRegistrar Registration Expiration Date:\nRegistrar: Instra Corporation Pty Ltd.\nRegistrar IANA ID: 1376\nRegistrar Abuse Contact Email:\nRegistrar Abuse Contact Phone:\nReseller:\nDomain Status: serverTransferProhibited https:\/\/icann.org\/epp#serverTransferProhibited\nRegistrant Organization:\nRegistrant State\/Province: podkarpackie\nRegistrant Country: PL\nName Server: NS1.ZENBOX.PL\nName Server: NS2.ZENBOX.PL\nDNSSEC: unsigned\nURL of the ICANN Whois Inaccuracy Complaint Form https:\/\/www.icann.org\/wicf\/)\n>>> Last update of WHOIS database: 2018-09-15T19:17:34Z <<<\n\nFor more information on Whois status codes, please visit https:\/\/icann.org\/epp\n\nAccess to WHOIS information is provided to assist persons in determining the contents of a domain name registration record in the registry database. The data in this record is provided by The Registry Operator for informational purposes only, and accuracy is not guaranteed. This service is intended only for query-based access. You agree that you will use this data only for lawful purposes and that, under no circumstances will you use this data to (a) allow, enable, or otherwise support the transmission by e-mail, telephone, or facsimile of mass unsolicited, commercial advertising or solicitations to entities other than the data recipient's own existing customers; or (b) enable high volume, automated, electronic processes that send queries or data to the systems of Registry Operator, a Registrar, or Afilias except as reasonably necessary to register domain names or modify existing registrations. All rights reserved. Registry Operator reserves the right to modify these terms at any time. By submitting this query, you agree to abide by this policy.\n\nThe Registrar of Record identified in this output may have an RDDS service that can be queried for additional information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.", - "registrantContact": { - "name": "Registrant Country: PL", - "organization": "", - "street": "Registrant Country: PL", - "city": "", - "state": "podkarpackie", - "postalCode": "", - "country": "POLAND", - "email": "", - "telephone": "", - "telephoneExt": "", - "fax": "", - "faxExt": "", - "rawText": "Registrant Country: PL" - }, - "administrativeContact": { - "name": "", - "organization": "", - "street": "", - "city": "", - "state": "", - "postalCode": "", - "country": "", - "email": "", - "telephone": "", - "telephoneExt": "", - "fax": "", - "faxExt": "", - "rawText": "" - }, - "technicalContact": { - "name": "", - "organization": "", - "street": "", - "city": "", - "state": "", - "postalCode": "", - "country": "", - "email": "", - "telephone": "", - "telephoneExt": "", - "fax": "", - "faxExt": "", - "rawText": "" - }, - "billingContact": { - "name": "", - "organization": "", - "street": "", - "city": "", - "state": "", - "postalCode": "", - "country": "", - "email": "", - "telephone": "", - "telephoneExt": "", - "fax": "", - "faxExt": "", - "rawText": "" - }, - "zoneContact": { - "name": "", - "organization": "", - "street": "", - "city": "", - "state": "", - "postalCode": "", - "country": "", - "email": "", - "telephone": "", - "telephoneExt": "", - "fax": "", - "faxExt": "", - "rawText": "" - } - }, - { - "domainName": "coach.sex", - "domainType": "added", - "createdDateISO8601": "2018-08-01T20:47:08+00:00", - "updatedDateISO8601": null, - "expiresDateISO8601": "2019-08-01T20:47:08+00:00", - "createdDateRaw": "2018-08-01T20:47:08Z", - "updatedDateRaw": "", - "expiresDateRaw": "2019-08-01T20:47:08Z", - "audit": { - "createdDate": "2018-08-02T18:44:19+00:00", - "updatedDate": "2018-08-02T18:44:19+00:00" - }, - "nameServers": [ - "NS1.ONLYDOMAINS.COM", - "NS2.ONLYDOMAINS.COM", - "NS3.ONLYDOMAINS.COM" - ], - "whoisServer": "whois.nic.sex", - "registrarName": "Instra Corporation Pty Ltd.", - "status": [ - "serverTransferProhibited", - "addPeriod" - ], - "cleanText": "Domain Name: COACH.SEX\nRegistry Domain ID: D425500000050058539-AGRS\nRegistrar WHOIS Server:\nRegistrar URL: http:\/\/www.instra.com\nUpdated Date:\nCreation Date: 2018-08-01T20:47:08Z\nRegistry Expiry Date: 2019-08-01T20:47:08Z\nRegistrar Registration Expiration Date:\nRegistrar: Instra Corporation Pty Ltd.\nRegistrar IANA ID: 1376\nRegistrar Abuse Contact Email:\nRegistrar Abuse Contact Phone:\nReseller:\nDomain Status: serverTransferProhibited https:\/\/icann.org\/epp#serverTransferProhibited\nDomain Status: addPeriod https:\/\/icann.org\/epp#addPeriod\nRegistrant Organization:\nRegistrant State\/Province: podkarpackie\nRegistrant Country: PL\nName Server: NS1.ONLYDOMAINS.COM\nName Server: NS2.ONLYDOMAINS.COM\nName Server: NS3.ONLYDOMAINS.COM\nDNSSEC: unsigned\nURL of the ICANN Whois Inaccuracy Complaint Form https:\/\/www.icann.org\/wicf\/)\n>>> Last update of WHOIS database: 2018-08-02T18:43:18Z <<<\nFor more information on Whois status codes, please visit https:\/\/icann.org\/epp\nAccess to WHOIS information is provided to assist persons in determining the contents of a domain name registration record in the registry database. The data in this record is provided by The Registry Operator for informational purposes only, and accuracy is not guaranteed. This service is intended only for query-based access. You agree that you will use this data only for lawful purposes and that, under no circumstances will you use this data to (a) allow, enable, or otherwise support the transmission by e-mail, telephone, or facsimile of mass unsolicited, commercial advertising or solicitations to entities other than the data recipient's own existing customers; or (b) enable high volume, automated, electronic processes that send queries or data to the systems of Registry Operator, a Registrar, or Afilias except as reasonably necessary to register domain names or modify existing registrations. All rights reserved. Registry Operator reserves the right to modify these terms at any time. By submitting this query, you agree to abide by this policy.\nPlease query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.\n", - "rawText": "Domain Name: COACH.SEX\nRegistry Domain ID: D425500000050058539-AGRS\nRegistrar WHOIS Server:\nRegistrar URL: http:\/\/www.instra.com\nUpdated Date:\nCreation Date: 2018-08-01T20:47:08Z\nRegistry Expiry Date: 2019-08-01T20:47:08Z\nRegistrar Registration Expiration Date:\nRegistrar: Instra Corporation Pty Ltd.\nRegistrar IANA ID: 1376\nRegistrar Abuse Contact Email:\nRegistrar Abuse Contact Phone:\nReseller:\nDomain Status: serverTransferProhibited https:\/\/icann.org\/epp#serverTransferProhibited\nDomain Status: addPeriod https:\/\/icann.org\/epp#addPeriod\nRegistrant Organization:\nRegistrant State\/Province: podkarpackie\nRegistrant Country: PL\nName Server: NS1.ONLYDOMAINS.COM\nName Server: NS2.ONLYDOMAINS.COM\nName Server: NS3.ONLYDOMAINS.COM\nDNSSEC: unsigned\nURL of the ICANN Whois Inaccuracy Complaint Form https:\/\/www.icann.org\/wicf\/)\n>>> Last update of WHOIS database: 2018-08-02T18:43:18Z <<<\n\nFor more information on Whois status codes, please visit https:\/\/icann.org\/epp\n\nAccess to WHOIS information is provided to assist persons in determining the contents of a domain name registration record in the registry database. The data in this record is provided by The Registry Operator for informational purposes only, and accuracy is not guaranteed. This service is intended only for query-based access. You agree that you will use this data only for lawful purposes and that, under no circumstances will you use this data to (a) allow, enable, or otherwise support the transmission by e-mail, telephone, or facsimile of mass unsolicited, commercial advertising or solicitations to entities other than the data recipient's own existing customers; or (b) enable high volume, automated, electronic processes that send queries or data to the systems of Registry Operator, a Registrar, or Afilias except as reasonably necessary to register domain names or modify existing registrations. All rights reserved. Registry Operator reserves the right to modify these terms at any time. By submitting this query, you agree to abide by this policy.\n\nPlease query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant, Admin, or Tech contact of the queried domain name.", - "registrantContact": { - "name": "Registrant Country: PL", - "organization": "", - "street": "Registrant Country: PL", - "city": "", - "state": "podkarpackie", - "postalCode": "", - "country": "POLAND", - "email": "", - "telephone": "", - "telephoneExt": "", - "fax": "", - "faxExt": "", - "rawText": "Registrant Country: PL" - }, - "administrativeContact": { - "name": "", - "organization": "", - "street": "", - "city": "", - "state": "", - "postalCode": "", - "country": "", - "email": "", - "telephone": "", - "telephoneExt": "", - "fax": "", - "faxExt": "", - "rawText": "" - }, - "technicalContact": { - "name": "", - "organization": "", - "street": "", - "city": "", - "state": "", - "postalCode": "", - "country": "", - "email": "", - "telephone": "", - "telephoneExt": "", - "fax": "", - "faxExt": "", - "rawText": "" - }, - "billingContact": { - "name": "", - "organization": "", - "street": "", - "city": "", - "state": "", - "postalCode": "", - "country": "", - "email": "", - "telephone": "", - "telephoneExt": "", - "fax": "", - "faxExt": "", - "rawText": "" - }, - "zoneContact": { - "name": "", - "organization": "", - "street": "", - "city": "", - "state": "", - "postalCode": "", - "country": "", - "email": "", - "telephone": "", - "telephoneExt": "", - "fax": "", - "faxExt": "", - "rawText": "" - } - } - ] -} \ No newline at end of file diff --git a/communication_subroutine.py b/communication_subroutine.py index bc44fff..41c8e17 100644 --- a/communication_subroutine.py +++ b/communication_subroutine.py @@ -1,11 +1,11 @@ -import logging -import threading import json -import time +import logging import re +import threading +import time +from queue import Empty, Queue from urllib import request as urequest -from queue import Queue, Empty from flask import Flask, jsonify, request from waitress import serve @@ -14,28 +14,30 @@ PORT_ADDRESS = 5000 ICECAST_ADDRESS = "http://192.168.1.15:8000" OUT_COMM_Q = Queue() IN_COMM_Q = Queue() -SRCHTITLE = re.compile(br'StreamTitle=\\*(?P[^;]*);').search +SRCHTITLE = re.compile(rb"StreamTitle=\\*(?P<title>[^;]*);").search awaiting_q = [] incoming_q = Queue() app = Flask(__name__) PREPPED_TRACKS = { - "requests" : "", - "hit" : "", + "requests": "", + "hit": "", "all": "", - "priority":"", - "jingles":"", - "now_playing":"", + "priority": "", + "jingles": "", + "now_playing": "", "next": "", - "meta" : "" + "meta": "", } logger = logging.getLogger("discord") + class QueryControl: """ This class `QueryControl` is used to manage queries with information about the author, UUID, content, logger, context, and replies. """ + def __init__(self, query_author, query_uuid, query_content, ctx) -> None: self.author = query_author self.uuid = query_uuid @@ -48,6 +50,7 @@ class QueryControl: ) self.replies = [] + @app.route("/prepped_tracks", methods=["POST"]) def log_radio_tracks(): app.logger = logging.getLogger("discord") @@ -59,7 +62,14 @@ def log_radio_tracks(): metadata = id3(ICECAST_ADDRESS) PREPPED_TRACKS["now_playing"] = PREPPED_TRACKS["next"] if metadata: - PREPPED_TRACKS["meta"] = metadata["name"] + " - " + metadata["title"] + "(" + metadata["genre"] + ")" + PREPPED_TRACKS["meta"] = ( + metadata["name"] + + " - " + + metadata["title"] + + "(" + + metadata["genre"] + + ")" + ) else: PREPPED_TRACKS["meta"] = "Nie znaju" PREPPED_TRACKS[record[0]] = record[1] @@ -83,6 +93,7 @@ def answer_external_command(): incoming_q.put(record) return jsonify("SUCCESS") + @app.route("/conjurer", methods=["GET"]) def check_alive(): """ @@ -94,6 +105,7 @@ def check_alive(): """ return jsonify("ALIVE") + def flask_debug(): """ The `flask_debug` function starts a Flask application in debug mode without using the reloader. @@ -116,6 +128,7 @@ def waitress_run(): logger.info("Attempt waitress") serve(app, host=HOST_ADDRESS, port=PORT_ADDRESS) + def scan_queue(): """ The function `scan_queue` reads data from a queue, logs it, and appends it to another queue. @@ -131,6 +144,7 @@ def scan_queue(): logger.info(data) awaiting_q.append(data) + def scan_incoming(): """ The `scan_incoming` function continuously checks for incoming data, processes it, and logs when data @@ -162,26 +176,31 @@ def scan_incoming(): except Empty: time.sleep(1) -def get_stream_title(tag:bytes) -> str: - title = '' + +def get_stream_title(tag: bytes) -> str: + title = "" if m := SRCHTITLE(tag): - #decode, strip, unescape and remove surrounding quotes (may not even be the same type of quote) - title = m.group('title').decode('utf-8').strip().replace('\\', '')[1:-1] + # decode, strip, unescape and remove surrounding quotes (may not even be the same type of quote) + title = m.group("title").decode("utf-8").strip().replace("\\", "")[1:-1] return title -def id3(url:str) -> dict: - request = urequest.Request(url, headers={'Icy-MetaData': 1}) + +def id3(url: str) -> dict: + request = urequest.Request(url, headers={"Icy-MetaData": 1}) with urequest.urlopen(request) as resp: - metaint = int(resp.headers.get('icy-metaint', '-1')) - if metaint<0: + metaint = int(resp.headers.get("icy-metaint", "-1")) + if metaint < 0: return False - resp.read(metaint) #this isn't seekable so, arbitrarily read to the point we want + resp.read( + metaint + ) # this isn't seekable so, arbitrarily read to the point we want tagdata = dict( - site_url = resp.headers.get('icy-url' ) , - name = resp.headers.get('icy-name' ).title(), - genre = resp.headers.get('icy-genre').title(), - title = get_stream_title(resp.read(255)) ) + site_url=resp.headers.get("icy-url"), + name=resp.headers.get("icy-name").title(), + genre=resp.headers.get("icy-genre").title(), + title=get_stream_title(resp.read(255)), + ) return tagdata @@ -193,20 +212,20 @@ def comm_subroutine(): object that is used for logging messages at various levels (e.g., debug, info, warning, error). In the provided code snippet, the logger is used to log messages at the "info" level """ - #logger.setLevel(logging.DEBUG) + # logger.setLevel(logging.DEBUG) logger = logging.getLogger("discord") logger.info("Started comms") threads = [] - #threads.append(threading.Thread(target=flask_debug)) + # threads.append(threading.Thread(target=flask_debug)) threads.append(threading.Thread(target=waitress_run)) threads.append(threading.Thread(target=scan_queue)) threads.append(threading.Thread(target=scan_incoming)) - for worker in threads: worker.start() for worker in threads: worker.join() + if __name__ == "__main__": comm_subroutine() diff --git a/conjurer_musician/radio_conjurer.liq b/conjurer_musician/radio_conjurer.liq index 77c4e42..143f3b8 100644 --- a/conjurer_musician/radio_conjurer.liq +++ b/conjurer_musician/radio_conjurer.liq @@ -76,15 +76,16 @@ mic = compress(threshold=0., ratio=2.,mic) mic = blank.strip(max_blank=10., min_noise=.1, threshold=-20., mic) s = add([s, mic]) - # Apply audio processing effects s = nrj(normalize(s)) s = amplify(a, s) - - # Skip blank sections in the stream s = blank.skip(max_blank=10., s) +#Manual audition override +source_control = interactive.bool("Source control", true) +s = switch(track_sensitive=false, [(source_control,mic),({true},s)]) + # Configure logging settings log_to_stdout = true log_to_file = true @@ -102,7 +103,6 @@ emergency = single("/home/pi/RetroPie/mp3/Youtube/Dr. Peacock - Trip to Ireland radio = fallback(id="switcher2", track_sensitive=false, [s, emergency]) # Set up an interactive control for skipping tracks p = interactive.bool("Skip track", false) - def http_skip(~protocol, ~data, ~headers, uri)= radio.skip() http.response(code=200,data="Skipped") diff --git a/conjurer_musician/test_mic.liq b/conjurer_musician/test_mic.liq new file mode 100644 index 0000000..e005ed8 --- /dev/null +++ b/conjurer_musician/test_mic.liq @@ -0,0 +1,23 @@ +tmic = buffer(input.pulseaudio()) # Microphone + +if tmic.is_active() then + log.info("Buffer active") +end + +if tmic.is_ready() then + log.info("Buffer ready") +end +if tmic.is_up() then + log.info("Buffer up") +end + +interactive.harbor(port = 9999) + +mic_gain = interactive.float("mic_volume", min=0., max=20., 6.) + +mic = amplify(mic_gain, tmic) +#mic = gate(threshold=-80., range=-120., mic) +#mic = compress(threshold=0., ratio=2.,mic) +#mic = blank.strip(max_blank=10., min_noise=.1, threshold=-20., mic) + +output.pulseaudio(mic) diff --git a/constants.py b/constants.py new file mode 100644 index 0000000..267a3b3 --- /dev/null +++ b/constants.py @@ -0,0 +1,137 @@ +import json +import netrc +from datetime import datetime +from platform import uname +from sys import platform +from typing import List, Optional, TypedDict + +import openai +import spotipy +from spotipy.oauth2 import SpotifyClientCredentials + +Music_Config = TypedDict( + "Music_Config", + { + "ctx": Optional[str], + "queue": List[str], + "requester": List[str], + }, +) + + +# *=========================================== Predefines +MASTER_TIMEOUT = datetime.now() +INITIAL_TIME_WAIT = 500 +MUZYKA: Music_Config = {"ctx": None, "queue": [], "requester": []} + +LOGFILE = "" +NETRC_FILE = "" +MUSIC_FOLDER = "" +MEMORY_FIVE_SIARA = "" +MEMORY_FIVE_MUZYKA = "" +SETTINGS_FILE = "" +ENCODING = "" +GRAPHICS_PATH = "" +MUZYKA_MOJEGO_LUDU_HISTORIA = 1500 +MUZYKA_MOJEGO_LUDU_SLOWA_KLUCZOWE = 15 +MUZYKA_MOJEGO_LUDU_PLAJLISTA = 30 + +FILE_SERVICE_ADDRESS = "http://192.168.1.15:5000" +RADIO_HARBOR_ADDRESS = "http://192.168.1.15:54321" +SKIP_TRACK = "/skip" + +GET_MP3 = "/mp3" +SEND_MP3 = "/update_mp3" +GET_PLAYLIST = "/get_music" +ADD_TO_PRIO_PLAYLIST = "/add_to_priority" +CREATE_PRIO_PLAYLIST = "/create_priority_playlist" + +REQUEST_MUSIC = "/request_radio_file" +CLEAR_PRIO = "/clear_pr_pls" +LIBRARIAN_SERVICE_ADDRESS = "http://192.168.1.192:5001" +SEND_QUERY = "/query" +TIME_BETWEEN_CALLS = 100000 +LAST_SPONTANEOUS_CALL = datetime.now() +HOST_ADDRESS = "192.168.1.191" +PORT_ADDRESS = 5000 + +# *=========================================== Platform Specific Predefines + +if platform in ("linux", "linux2"): + SEPARATOR_FILE_PATH = "/" + if "microsoft-standard" in uname().release: + LOGFILE = "/home/mtuszowski/conjurer/discord.log" + MEMORY_FIVE_SIARA = "/home/mtuszowski/conjurer/pamiec.json" + SYSTEM_GPT_SETTINGS = "/home/mtuszowski/conjurer/system_gpt_settings.json" + MEMORY_FIVE_MUZYKA = "/home/mtuszowski/conjurer/pamiec_muzyki.json" + MUSIC_FOLDER = "/mnt/g/Muzyka/" + SETTINGS_FILE = "/home/mtuszowski/conjurer/settings.json" + NETRC_FILE = "/home/mtuszowski/.netrc" + LOGSTORE = "/home/mtuszowski/conjurer/logs/" + ACCIDENT_LOG = "/home/mtuszowski/conjurer/accident_log.json" + ENCODING = "utf-8" + GRAPHICS_PATH = "/home/mtuszowski/conjurer/Conjurer_graphics/" + DIR_PATH_SADOX = "/mnt/c/Users/mtusz/OneDrive/Dokumenty/Fansadox" + + else: + LOGFILE = "/home/pi/Conjurer/discord.log" + MEMORY_FIVE_SIARA = "/home/pi/Conjurer/pamiec.json" + SYSTEM_GPT_SETTINGS = "/home/pi/Conjurer/system_gpt_settings.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/" + DIR_PATH_SADOX = "/home/pi/RetroPie/Fansadox/" + + +elif platform == "win32": + LOGFILE = "discord.log" + MEMORY_FIVE_SIARA = "pamiec.json" + SYSTEM_GPT_SETTINGS = "system_gpt_settings.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 = "utf-8" + DIR_PATH_SADOX = "C:\\Users\\mtusz\\OneDrive\\Dokumenty\\Fansadox\\" + SEPARATOR_FILE_PATH = "\\" +with open(SETTINGS_FILE, "r", encoding=ENCODING) as f_settings_file: + DATA = json.load(f_settings_file) +REMOTE_HOST_NAME = "openai" +netrc_mod = netrc.netrc(NETRC_FILE) +authTokens = netrc_mod.authenticators(REMOTE_HOST_NAME) +openai.api_key = authTokens[2] +OPENAICLIENT = openai.AsyncOpenAI(api_key=openai.api_key) +REMOTE_HOST_NAME = "discord" +authTokens = netrc_mod.authenticators(REMOTE_HOST_NAME) +TOKEN = authTokens[2] + +REMOTE_HOST_NAME = "spotipy" +authTokens = netrc_mod.authenticators(REMOTE_HOST_NAME) +SPOTIFY_CTRL = spotipy.Spotify( + client_credentials_manager=SpotifyClientCredentials( + client_id=authTokens[0], + client_secret=authTokens[2], + ) +) + +WORD_REACTIONS = DATA["word_reactions"] +CYCLIC_WORDS = DATA["cyclic_words"] +for key in WORD_REACTIONS: + WORD_REACTIONS[key][2] = datetime.now() +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(SYSTEM_GPT_SETTINGS, "r+", encoding=ENCODING) as temp_settings_file: + # First we load existing data into a dict. + GPT_SETTINGS = json.load(temp_settings_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) diff --git a/deploy.sh b/deploy.sh index f934f51..75b6639 100755 --- a/deploy.sh +++ b/deploy.sh @@ -1,9 +1,27 @@ #!/bin/bash +cd /home/pi/conjurer || exit git pull -cd .. -cp ./conjurer/bot.py ./Conjurer/ +cp ./deploy.sh /home/pi/ +cd /home/pi || exit +#cp ./conjurer/bot.py ./Conjurer/ #legacy to be deprecated after refactor is done + + cp ./conjurer/settings.json ./Conjurer/ cp ./conjurer/system_gpt_settings.json ./Conjurer/ -cp ./conjurer/install.sh ./Conjurer/ -cp ./conjurer/requirements.txt ./Conjurer/requirements.txt + + +cp ./conjurer/administration_commands.py ./Conjurer/ +cp ./conjurer/ai_commands.py ./Conjurer/ +cp ./conjurer/ai_functions.py ./Conjurer/ +cp ./conjurer/communication_subroutine.py ./Conjurer/ +cp ./conjurer/constants.py ./Conjurer/ +cp ./conjurer/librarian_commands.py ./Conjurer/ +cp ./conjurer/music_commands.py ./Conjurer/ +cp ./conjurer/music_functions.py ./Conjurer/ +cp ./conjurer/other_commands.py ./Conjurer/ +cp ./conjurer/other_functions.py ./Conjurer/ +cp ./conjurer/radio_commands.py ./Conjurer/ +cp ./conjurer/voice_recognition_commands.py ./Conjurer/ +cp ./conjurer/thin_client.py ./Conjurer/bot.py + sudo systemctl restart conjurer.service diff --git a/deploy_music.sh b/deploy_music.sh index 59873cb..7914d31 100755 --- a/deploy_music.sh +++ b/deploy_music.sh @@ -1,5 +1,5 @@ #!/bin/bash -cd ./conjurer +cd ./conjurer || exit git pull cd .. cp ./conjurer/conjurer_musician/conjurer_musician.py ./Conjurer diff --git a/install_main_bot.sh b/install_main_bot.sh index 4eb0f03..ac58dcb 100755 --- a/install_main_bot.sh +++ b/install_main_bot.sh @@ -1,11 +1,12 @@ #!/bin/bash sudo apt-get install python3-dev -cd /home/pi +cd /home/pi || exit mdkir Conjurer -cd Conjurer -python3 -m venv /home/pi/Conjurer/env +cd Conjurer ||exit +python3 -m venv /home/pi/Conjurer/.venv cp /home/pi/conjurer/requirements_bot.txt /home/pi/Conjurer/ -source ./env/bin/activate +# trunk-ignore(shellcheck/SC1091) +source /home/pi/Conjurer/.venv/bin/activate ./env/bin/python3 -m pip install --upgrade pip ./env/bin/python3 -m pip install -r requirements_bot.txt sed -i -e 's/os.rename/shutil.copy/g' ./env/lib/python3.11/site-packages/spotify_dl/youtube.py @@ -14,7 +15,7 @@ sed -i '1i\import logging' ./env/lib/python3.11/site-packages/spotify_dl/spotify sed -i '21i\ logger = logging.getLogger("discord")' ./env/lib/python3.11/site-packages/spotify_dl/spotify.py sed -i '22i\ logger.info("Playlist")' ./env/lib/python3.11/site-packages/spotify_dl/spotify.py - +#add sed changing signal registration to catch exception in spotify dl init deactivate sudo cp ./conjurer.service /etc/systemd/system/ sudo systemctl daemon-reload diff --git a/install_music_bot.sh b/install_music_bot.sh index 3d1364a..a93163a 100755 --- a/install_music_bot.sh +++ b/install_music_bot.sh @@ -19,6 +19,15 @@ touch /home/pi/Conjurer/request.playlist touch /home/pi/Conjurer/persistence.log echo "[]" > /home/pi/Conjurer/persistence.log +sudo usermod -aG pulse-access pi +sudo usermod -aG pulse-access root + +sudo usermod -aG audio pi +sudo usermod -aG audio root + + + + touch /home/pi/Conjurer/radio_log.log ./env/bin/python3 -m pip install --upgrade pip ./env/bin/python3 -m pip install -r requirements_musician.txt diff --git a/librarian_commands.py b/librarian_commands.py new file mode 100644 index 0000000..e3c67e8 --- /dev/null +++ b/librarian_commands.py @@ -0,0 +1,285 @@ +import asyncio +import io +import logging +import os +import random +import uuid +from queue import Empty + +import discord +import pdf2image +import PyPDF2 +import requests +from discord.ext import commands, tasks + +from ai_functions import handle_response +from communication_subroutine import IN_COMM_Q, OUT_COMM_Q, QueryControl +from constants import DIR_PATH_SADOX, LIBRARIAN_SERVICE_ADDRESS, SEND_QUERY + + +class DataModule(commands.Cog): + def __init__(self, bot, logger_name): + self.bot = bot + self.logger = logging.getLogger(logger_name) + + @commands.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(self, ctx): + """ + Take in a context parameter and retrieve an image related from fansadox collection. + + :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. In this case, it is likely being used + to determine + """ + self.logger.info("Get sadox") + channel = ctx.message.channel + async with channel.typing(): + # select random file + 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) + # trunk-ignore(bandit/B311) + 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) + # trunk-ignore(bandit/B311) + 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) + self.logger.info("Get sadox completed") + + # TODO: LIBRARIAN + @tasks.loop(seconds=3) + async def check_data_q(self): + """ + This function checks the data queue for any new entries and processes them accordingly. + """ + try: + fresh_data = IN_COMM_Q.get(block=False) + entries = [] + if fresh_data.stop: + searcher = fresh_data.author + query = fresh_data.content + l_p = 1 + for doi in fresh_data.entries: + self.logger.info(doi) + desc = fresh_data.entries[doi] + title = desc["Title"][0] + entries.append( + f"{l_p}. {title} pod linkiem https://www.sci-hub.se/{doi} i jest to {desc['type']}\n" + ) + l_p += 1 + message = "*Z podłogi wysuwa się winda na książki*" + if fresh_data.ctx is not None: + ctx = fresh_data.ctx + message += f" Dzielny poszukiwaczu @{searcher} w odpowiedzi na twoje zapytanie {query} nr {fresh_data.uuid}" + else: + ctx = self.bot.get_channel(1062047571557744721) + message += f" Mam wynik dla zapytania {fresh_data.uuid} ale że Hammer coś grzebał nie pamiętam kto to chciał i co chciał" + + message += "nasza biblioteka służy Ci odpowiedzią. Przy dźwięku fanfar winda się otwiera a w środku " + if len(entries) < 1: + message += "niestety nie ma nic" + await ctx.send(message) + elif len(entries) >= 1 and len(entries) < 5: + message += " znajduje się coś:\n" + for item in entries: + message += item + await ctx.send(message) + else: + message += " znajduje się cholernie dużo:\n" + for item in entries: + message += item + if len(message) > 1500: + await ctx.send(message) + message = "" + + # Kept for sentimental reasons + # await ctx.send(f"O. A tak będzie wyglądało coś ciekawego w przyszłości: {data}") + except Empty: + pass + + # TODO: LIBRARIAN + @commands.hybrid_command( + name="wyszukaj_linki_do_dokumentow", + description="Szuka linkow doi w bazie crossref i podaje linki do scihuba", + guild=discord.Object(id=664789470779932693), + ) + async def wyszukaj_linki_do_dokumentow(self, ctx): + """ + The function `wyszukaj_linki_do_dokumentow` searches for links to documents in a crossref database and provides links to scihub. + + :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. + """ + query = ctx.message.content + query_uuid = uuid.uuid4() + # TODO: TESTING ONLY!! + # query_uuid = uuid.UUID('{12345678-1234-5678-1234-567812345678}') + ctx.message.content = ctx.message.content.replace( + "$wyszukaj_linki_do_dokumentow", "" + ) + + json_query = { + "UUID": str(query_uuid), + "query": str(query), + "page": 1, + "deep_search": False, + } + coroutine = asyncio.to_thread( + requests.post, + f"{LIBRARIAN_SERVICE_ADDRESS}{SEND_QUERY}", + json=json_query, + timeout=360, + ) + await ctx.send( + "*Conjurer powoli notuje podane przez Ciebie. Podchodzi do sprytnie ukrytej przy barze rury od poczty pneumatycznej i" + + " wrzuca twój liścik do środka* To teraz trza poczekać kilka godzin. Biblioteka to 3/4 stacji." + + " A przecież pół stacji to browar, motelik dla zabaw cielesnych i ten Bar. Więc 12/8 stacji teraz będzie ciężko pracować" + ) + query_response = await coroutine + if not query_response.status_code == 200: + await ctx.send( + "*Z rury wydobywa się dym. Conjurer łapie pierwszą ciecz pod ręką i pryska na rurę. Następuje drobna eksplozja i wszystko zaczyna się palić." + + " Conjurer jest skonfundowany..* Wołaj szefa - mam nieodparte wrażenie że się coś wyjebało" + ) + return + + query, query_uuid, queue_size = ( + query_response.json()["data"][0], + query_response.json()["data"][1], + query_response.json()["data"][2], + ) + if ctx.message.author.nick: + username = ctx.message.author.nick + else: + username = ctx.message.author.name + query_object = QueryControl(username, query_uuid, query, ctx) + OUT_COMM_Q.put(query_object) + await ctx.send( + f"No dobra poszło. Zapamiętaj proszę {query_uuid} - to identyfikator twojego zapytania. Jesteś {queue_size} w kolejce." + + " Zapytania obsługuje algorytm zasilany czterema chomikami zapierdalającymi w kołowrotku - więc wyniki najwcześniej za kilka godzi - ale mogą być też dni." + ) + + # TODO: LIBRARIAN + @commands.hybrid_command( + name="glebokie_gardlo", + description="Przygotowuje drinka o nazwie głębokie gardło", + guild=discord.Object(id=664789470779932693), + ) + async def wyszukaj_linki_do_dokumentow_deep(self, ctx): + """ + The function `wyszukaj_linki_do_dokumentow_deep` performs a deep search for links to documents in + a crossref database and provides links to scihub. + + :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. + """ + # TODO: Implement deep search logic here + query = ctx.message.content.replace("$glebokie_gardlo", "") + allowed = False + for role in ctx.message.author.roles: + if role.name == "Bartender": + allowed = True + if role.name == "Scribe": + allowed = True + if role.name == "Thane": + allowed = True + if not allowed: + if ctx.message.author.nick: + username = ctx.message.author.nick + else: + username = ctx.message.author.name + vykidailo = False + bartender = False + prompt = "Przygotuj mi drinka o nazwie Głębokie Gardło, inspirowanego tym sławnym filmem oraz skandalem Watergate" + for role in ctx.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, "CONVERSATION" + ) + if len(result) < 1500: + await ctx.send(result) + else: + while len(result) > 1500: + await ctx.send(result[:1500]) + result = result[1500:] + return + + query_uuid = uuid.uuid4() + # TODO: TESTING ONLY!! + # query_uuid = uuid.UUID('{12345678-1234-5678-1234-567812345678}') + json_query = { + "UUID": str(query_uuid), + "query": str(query), + "page": 1, + "deep_search": True, + } + coroutine = asyncio.to_thread( + requests.post, + f"{LIBRARIAN_SERVICE_ADDRESS}{SEND_QUERY}", + json=json_query, + timeout=360, + ) + await ctx.send( + "*Conjurer mruga okiem i zamiast drinka wyjmuje dysk usb z terminala. Podchodzi do sprytnie ukrytej przy barze rury od poczty pneumatycznej i" + + " wrzuca ten dysk do środk* To teraz trza poczekać kilka godzin. TO będzie głębokie wyszukanie" + + " Rozgląda się dookoła i stawia przed tobą mętnego drinka o zapachu mięty, gwiezdnego pyłu i oleju silnikowego" + ) + query_response = await coroutine + if not query_response.status_code == 200: + await ctx.send( + "*Z rury wydobywa się dym. Conjurer łapie pierwszą ciecz pod ręką i pryska na rurę. Następuje drobna eksplozja i wszystko zaczyna się palić." + + " Conjurer jest skonfundowany..* Wołaj szefa - mam nieodparte wrażenie że się coś wyjebało" + ) + return + + query, query_uuid, queue_size = ( + query_response.json()["data"][0], + query_response.json()["data"][1], + query_response.json()["data"][2], + ) + if ctx.message.author.nick: + username = ctx.message.author.nick + else: + username = ctx.message.author.name + query_object = QueryControl(username, query_uuid, query, ctx) + OUT_COMM_Q.put(query_object) + await ctx.send( + f"Wypij wypi {query_uuid} - to identyfikator twojego zapytania. Jesteś {queue_size} w kolejce niestety kolejka obowiazuje zawsze." + + " Zapytania obsługuje algorytm zasilany czterema chomikami zapierdalającymi w kołowrotku - więc wyniki najwcześniej za kilka godzin - ale mogą być też dni. Głębokie zabawy trwają dłużej. *Znowu mruga*" + ) + + +async def setup(bot): + logger = logging.getLogger("discord") + dm = DataModule(bot, "discord") + dm.check_data_q.start() + await bot.add_cog(dm) + logger.info("Loading data sharing commands module done") diff --git a/music_commands.py b/music_commands.py new file mode 100644 index 0000000..4a1b7f1 --- /dev/null +++ b/music_commands.py @@ -0,0 +1,713 @@ +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", + ) + 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ę") + allowed = False + for role in ctx.author.roles: + if role.name == "Bartender": + allowed = True + if allowed: + 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})" + ) + else: + await ctx.reply("Jak ładnie szefa poprosisz.") + + @commands.hybrid_command( + name="co_na_plejliscie_wariacie", + description="Wyswietl kawalki ktore sa na pocztku list radia", + guild=discord.Object(id=664789470779932693), + ) + 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), + ) + 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), + ) + 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), + ) + 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), + ) + 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") + + # TODO: MUSIC + @commands.hybrid_command( + name="daj_mi_chwile", + description="Pauzuje", + guild=discord.Object(id=664789470779932693), + ) + 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") + + # TODO: MUSIC + @commands.hybrid_command( + name="graj_dalej", + description="Odpauzowuje", + guild=discord.Object(id=664789470779932693), + ) + 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") + + # TODO: MUSIC + @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), + ) + 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" + ) + + # TODO: MUSIC + @commands.hybrid_command( + name="zrob_mi_plejliste", + description="Generuje playliste - param1 - dlugosc, potem slowa wyszukiwania", + guild=discord.Object(id=664789470779932693), + ) + 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") + + # TODO: MUSIC + @commands.hybrid_command( + name="zagraj_muzyke_mego_ludu", + description="Gra muzyke wyszukana na bazie tematow konwersacji na kanale NZ", + guild=discord.Object(id=664789470779932693), + ) + 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") + + # TODO: MUSIC + @commands.hybrid_command( + name="parametry_muzyki_mego_ludu", + description="Konfiguruje komende zagraj muzyke mojego ludu", + guild=discord.Object(id=664789470779932693), + ) + 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), + ) + 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") + + 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") + music_functions.MUSIC_FILE_LIST.refresh_file_list() + logger.info("Playlist generation") + await bot.add_cog(MusicModule(bot, "discord")) + logger.info("Loading music commands module done") diff --git a/music_functions.py b/music_functions.py new file mode 100644 index 0000000..bb005c5 --- /dev/null +++ b/music_functions.py @@ -0,0 +1,285 @@ +import asyncio +import logging +import re +import uuid +from pathlib import Path, PurePath +from sys import platform + +import requests + +import yt_dlp +from constants import ( + FILE_SERVICE_ADDRESS, + GET_MP3, + GET_PLAYLIST, + MUSIC_FOLDER, + SEND_MP3, + SPOTIFY_CTRL, +) +from spotify_dl import spotify +from spotify_dl import youtube as youtube_download + +logger = logging.getLogger("discord") + + +class MusicFileList(object): + """ + The `MusicFileList` class manages a list of music files, with the ability to refresh the list from a + file service or local directory and update the list with new items. + """ + + def __init__(self, uplogger) -> None: + self.music_file_list = [] + self.file_service_active = False + self.logger = uplogger + self.logger.info("Created Playlist organizer class") + + def refresh_file_list(self): + """ + The `refresh_file_list` function attempts to connect to a file service to retrieve a list of music + files, and if unsuccessful, it populates the list by scanning a local directory for .mp3 files. + """ + try: + self.logger.info("Attempt to connect to file service") + response = requests.get(f"{FILE_SERVICE_ADDRESS}{GET_MP3}", timeout=360) + self.music_file_list = response.json()["music_file_list"] + self.file_service_active = True + except requests.exceptions.RequestException as e: + 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("/", "\\") + self.music_file_list.append(temp_music_file) + self.file_service_active = False + self.logger.error(e.strerror) + self.logger.error("Service Unavailable") + + def get_file_list(self): + """ + The `get_file_list` function returns the list of music files stored in the object. + :return: The `music_file_list` attribute is being returned. + """ + return self.music_file_list + + def update_file_list(self, item): + """ + The `update_file_list` function appends an item to a music file list and sends a POST request with + the item data to a file service address. + + :param item: The `item` parameter in the `update_file_list` method is the file that you want to add + to the `music_file_list` attribute of the class instance. It is then sent as a JSON payload in a + POST request to a file service address along with the endpoint `SEND_MP3` + """ + self.music_file_list.append(item) + post_data = {"item": str(item)} + requests.post(f"{FILE_SERVICE_ADDRESS}{SEND_MP3}", json=post_data, timeout=360) + + +MUSIC_FILE_LIST = MusicFileList(logger) + + +async def get_file(ctx, source, link): + """ + Take in three parameters: "ctx" (context), + "source" (a string representing the source of the file), and "link" (a string representing the link + to the file). Execute it in asynchronouse way. And get file from spotify or youtube. + + :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 + :param source: The source parameter is likely a string that represents the source of the file that + the user wants to retrieve. This could be a website, a cloud storage service, or any other location + where the file is stored + :param link: The "link" parameter is likely a string that represents a URL or file path to the + location of the file that the function is trying to retrieve + """ + 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_type in ["album", "track", "playlist"] and item_id: + logger.info(item_type) + logger.info(item_id) + logger.info("Spotify link provided") + file_list = await asyncio.to_thread( + spotify.fetch_tracks, SPOTIFY_CTRL, item_type, link + ) + logger.info(file_list) + directory_name = await asyncio.to_thread( + spotify.get_item_name, SPOTIFY_CTRL, item_type, item_id + ) + logger.info(directory_name) + logger.info("Spotify scrape done") + 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 + logger.info("YT-DL") + coro = asyncio.to_thread( + 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="", + ) + _ = await coro + logger.info("YT-DL done") + dir_path = (url_dict["save_path"].resolve()).as_posix() + if platform == "win32": + dir_path = dir_path.replace("/", "\\") + return dir_path, file_list + + 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, + }, + ] + # TODO: Make sponsorblock work + sponsorblock_postprocessor = [] + 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: + coro = asyncio.to_thread(ydl.download, [query]) + _ = await coro + 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 + 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 + elif source == "Pornol": + + 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, + }, + ] + # TODO: Make sponsorblock work + sponsorblock_postprocessor = [] + dir_path = "/home/pi/RetroPie/movies/porn" + ydl_opts = { + "postprocessors": sponsorblock_postprocessor, + "paths": {"home": dir_path}, + } + with yt_dlp.YoutubeDL(ydl_opts) as ydl: + try: + coro = asyncio.to_thread(ydl.download, [query]) + _ = await coro + 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 + ) + file_list.append("wiadomo co wiadomo gdzie") + return dir_path, file_list + + +async def search_music(ctx, how_many=0, slowa_kluczowe=None): + """ + Take in a context object and an optional integer parameter "how_many" and perform search + operation on music library. + + :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 + :param how_many: how_many is a parameter that specifies the number of search results to be returned. + It is an optional parameter with a default value of 0, which means that if no value is provided for + how_many, the function will return all search results, defaults to 0 (optional) + """ + # i sieć neuronową z możliwością wyrażenia opinii o dopasowaniu. + if slowa_kluczowe: + word_list = slowa_kluczowe + else: + word_list = ctx.message.content.split() + logger.info("Wyszukuje") + jrequest = { + "lista_slow": word_list, + "dlugosc_plejlisty": how_many, + "UUID": str(uuid.uuid4()), + } + coroutine = asyncio.to_thread( + requests.post, + f"{FILE_SERVICE_ADDRESS}{GET_PLAYLIST}", + json=jrequest, + timeout=360, + ) + return_data = await coroutine + if not return_data.status_code == 200: + await ctx.send("Wołaj szefa - coś się wyjebało") + return + logger.info(return_data.json()["data"]) + return return_data.json()["data"] diff --git a/other_commands.py b/other_commands.py new file mode 100644 index 0000000..22e4691 --- /dev/null +++ b/other_commands.py @@ -0,0 +1,191 @@ +import asyncio +import json +import logging +from datetime import datetime +from typing import Optional + +import discord +from discord.ext import commands + +from constants import ACCIDENT_LOG, DATA, ENCODING + +historia_fabryczki = DATA["fabryczka"] + + +class OtherModule(commands.Cog): + def __init__(self, bot, logger_name): + self.bot = bot + self.logger = logging.getLogger(logger_name) + + @commands.hybrid_command( + name="przytul", description="Przytul kogoś - daj mention po komendzie :)" + ) + async def przytul(self, ctx, arg: Optional[discord.Member] = None): + """ + Generate a text about hugging mentioned user. + + :param ctx: ctx stands for "context" and is a required parameter 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 + :param arg: arg is a parameter of the function "przytul" that expects a Discord member object. The + parameter is optional, meaning that if no member object is provided, it will default to None + :type arg: Optional[discord.Member] + """ + 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( + # trunk-ignore(codespell/misspelled) + 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*" + ) + + @commands.hybrid_command(name="fabryczka", description="Historia fabryczki") + async def fabryczka(self, ctx): + """ + Send a general description of "fabryczkagate" to channel. + + :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. The context object provides a way to + interact with the Discord + """ + await ctx.send(historia_fabryczki) + + @commands.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(self, ctx): + """ + Reset the clock on "accidents" in Hammer Fortress adding a new one. + + :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 + """ + 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? {self.bot.get_user(346956223645614080).mention} coś albo się komuś stało albo zaraz się stanie jak będzie zegar tykał...." + ) + + @commands.hybrid_command( + name="chata_hammera", + description="Czas od ostatniego incydentu w AbsinthHammerTimeSpaceContinuum", + ) + async def chata_hammera(self, ctx): + """ + Send measured time from last incident in Hammer Fortress to the chat. + + :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 + """ + 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}" + ) + + @commands.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(self, ctx): + """ + Send a list of incidents in Hammer Fortress to the chat. + + :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 + """ + 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) + + # TODO: RADIO + @commands.hybrid_command( + name="radio_hardkor", + description="Włącza radio Conjurer na kanale #nocna-zmiana.", + guild=discord.Object(id=664789470779932693), + ) + async def radio_hardkor(self, ctx): + """ + Plays the radio hardkor stream in the voice channel. + + Args: + ctx: The context object representing the invocation context. + + Returns: + None + """ + self.logger.info("Press play on radio hardkor") + async with ctx.typing(): + global MUZYKA # pylint: disable=global-variable-not-assigned + MUZYKA["ctx"] = ctx + if not self.bot.voice_clients: + await self.connect(ctx=ctx) + voice_client = self.bot.voice_clients[0] + voice_client.play( + discord.PCMVolumeTransformer( + discord.FFmpegPCMAudio("http://95.175.16.246:666/mp3-stream"), + volume=0.3, + ) + ) + self.logger.info("Press play on radio completed") + else: + self.logger.error("Already playing") + await asyncio.sleep(12) + self.check_music.start() + + +async def setup(bot): + logger = logging.getLogger("discord") + await bot.add_cog(OtherModule(bot, "discord")) + logger.info("Loading kitchen sink module done") diff --git a/other_functions.py b/other_functions.py new file mode 100644 index 0000000..58a69fc --- /dev/null +++ b/other_functions.py @@ -0,0 +1,88 @@ +# define an asynchronous generator +async def async_iterator_generator(range_of_iterable): + """ + Generate asynchronouse iterator. + This is an incomplete function definition for an asynchronous iterator generator that takes a range + of iterable as input. + + :param range_of_iterable: The parameter `range_of_iterable` is likely a range or iterable object + that the async iterator generator will iterate over asynchronously. It could be a list, tuple, set, + or any other iterable object. The generator will yield each item in the iterable object + asynchronously, allowing other code to run in between + """ + # normal loop + for i in range_of_iterable: + # pylint: disable=pointless-string-statement + # 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) + """ + + +# TODO: OTHER +async def remove_characters(string, character): + """ + The `remove_characters` function removes all occurrences of a specified character from a given + string. + + :param string: The string parameter is the input string from which characters will be removed + :param character: The character parameter is the character that you want to remove from the string + :return: a new string where all occurrences of the specified character have been removed. + """ + return string.replace(character, "") + + +# TODO: OTHER +async def max_weight(lista): + """ + Take a list of weights and return the maximum weight. + + :param lista: It seems like the parameter `lista` is a list of items, possibly representing weights. + The function name `max_weight` suggests that the function is intended to find the maximum weight + from the list. However, without more context or information about the problem, it's difficult to say + for sure what the + """ + maximum_weight = 0 + for iterator in lista: + if iterator[0] > maximum_weight: + maximum_weight = iterator[0] + return maximum_weight + + +async def get_stats(client, ctx, history_limit): + """ + The `get_stats` function retrieves the message history of a specific channel and counts the + frequency of each word in the messages. + + :param ctx: The `ctx` parameter is an object that represents the context of the command being + executed. It contains information such as the message, the author, the server, and other relevant + details + :param history_limit: The `history_limit` parameter is the maximum number of messages to retrieve + from the channel history. It determines how far back in time the statistics will be calculated + :return: The function `get_stats` returns a dictionary `stats` that contains the frequency count of + words found in the messages from the specified channel. + """ + channel_id = 1062047367337095268 + async with ctx.typing(): + stats = {} + channel = client.get_channel(channel_id) + messages = [message async for message in channel.history(limit=history_limit)] + # traverse the iterable of awaitables + for message in messages: + # await and get the result from the awaitable + result = message.content + words = result.split() + for word in words: + if word in stats: + stats[word] += 1 + else: + stats[word] = 1 + for name, how_many in stats.items(): + yield name, how_many diff --git a/radio_commands.py b/radio_commands.py new file mode 100644 index 0000000..53234a1 --- /dev/null +++ b/radio_commands.py @@ -0,0 +1,201 @@ +import logging +from discord.ext import commands +import discord +# trunk-ignore(bandit/B404) +import subprocess +import requests +import uuid + +import asyncio +from datetime import datetime +from constants import RADIO_HARBOR_ADDRESS, SKIP_TRACK, FILE_SERVICE_ADDRESS, ADD_TO_PRIO_PLAYLIST, REQUEST_MUSIC, CREATE_PRIO_PLAYLIST, CLEAR_PRIO + +class RadioModule(commands.Cog): + def __init__(self, bot, logger_name): + self.bot = bot + self.logger = logging.getLogger(logger_name) + + + @commands.hybrid_command( + name="skip_track", + description="Przeskocz kawałek w radiu", + guild=discord.Object(id=664789470779932693), + ) + async def skip_track(self, ctx): + async with ctx.typing(): + allowed = False + for role in ctx.author.roles: + if role.name in ("Thane", "Jarl"): + allowed = True + if not allowed: + await ctx.send("Łapy precz od radia") + else: + coroutine = asyncio.to_thread( + requests.get, + f"{RADIO_HARBOR_ADDRESS}{SKIP_TRACK}", + timeout=360, + ) + result = await coroutine + self.logger.info("Done %s", result) + await ctx.send("Zrobione szefie!") + + + @commands.hybrid_command( + name="zrestartuj_radio", + description="Komenda ktora uruchamia radio ponownie jakby się zawiesiło", + guild=discord.Object(id=664789470779932693), + ) + async def zrestartuj_radio(self, ctx): + async with ctx.typing(): + allowed = False + for role in ctx.author.roles: + if role.name in ("Thane", "Jarl"): + allowed = True + if not allowed: + await ctx.send("Łapy precz od radia") + else: + retcode = subprocess.run( + "/home/pi/Conjurer/restart_radio.sh", + # trunk-ignore(bandit/B603) + shell=False, + check=False, + capture_output=True, + ) + self.logger.info("Wynik: %s", retcode) + + @commands.hybrid_command( + name="dodaj_do_ulubionych", + description="Dodaje do listy ulubionych w radiu", + guild=discord.Object(id=664789470779932693), + ) + async def dodaj_do_ulubionych(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 + """ + async with ctx.typing(): + self.logger.info("Zaczynam szukać timestamp %s", datetime.now()) + + dlugosc_playlisty = ctx.message.content.split()[1] + word_list = ctx.message.content.split() + jrequest = { + "lista_slow": word_list, + "dlugosc_plejlisty": dlugosc_playlisty, + "UUID": str(uuid.uuid4()), + } + coroutine = asyncio.to_thread( + requests.post, + f"{FILE_SERVICE_ADDRESS}{ADD_TO_PRIO_PLAYLIST}", + json=jrequest, + timeout=360, + ) + result = await coroutine + self.logger.info("Done %s", result) + await ctx.send("Zrobione szefie!") + + + @commands.hybrid_command( + name="ja_chciol", + description="Dodaje do listy ulubionych w radiu", + guild=discord.Object(id=664789470779932693), + ) + async def request_radio(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 + """ + async with ctx.typing(): + self.logger.info("Zaczynam szukać timestamp %s", datetime.now()) + + word_list = ctx.message.content.split() + jrequest = { + "lista_slow": word_list, + "UUID": str(uuid.uuid4()), + } + coroutine = asyncio.to_thread( + requests.post, + f"{FILE_SERVICE_ADDRESS}{REQUEST_MUSIC}", + json=jrequest, + timeout=360, + ) + result = await coroutine + self.logger.info("Done %s", result) + await ctx.send("Zrobione szefie!") + + + @commands.hybrid_command( + name="stworz_audycje", + description="Dodaje do listy ulubionych w radiu", + guild=discord.Object(id=664789470779932693), + ) + async def stworz_audycje(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 + """ + async with ctx.typing(): + self.logger.info("Zaczynam szukać timestamp %s", datetime.now()) + + dlugosc_playlisty = ctx.message.content.split()[1] + word_list = ctx.message.content.split() + jrequest = { + "lista_slow": word_list, + "dlugosc_plejlisty": dlugosc_playlisty, + "UUID": str(uuid.uuid4()), + } + coroutine = asyncio.to_thread( + requests.post, + f"{FILE_SERVICE_ADDRESS}{CREATE_PRIO_PLAYLIST}", + json=jrequest, + timeout=360, + ) + result = await coroutine + self.logger.info("Done %s", result) + await ctx.send("Zrobione szefie!") + + + @commands.hybrid_command( + name="wyczysc_ulubione", + description="Czysci liste ulubionych w radiu", + guild=discord.Object(id=664789470779932693), + ) + async def wyczysc_ulubione(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 + """ + async with ctx.typing(): + coroutine = asyncio.to_thread( + requests.get, + f"{FILE_SERVICE_ADDRESS}{CLEAR_PRIO}", + timeout=360, + ) + result = await coroutine + self.logger.info("Done %s", result) + await ctx.send("Zrobione szefie!") + + +async def setup(bot): + logger = logging.getLogger("discord") + await bot.add_cog(RadioModule(bot, "discord")) + logger.info("Loading raadio commands module done") diff --git a/requirements_bot copy.txt b/requirements_bot copy.txt new file mode 100644 index 0000000..149dc14 --- /dev/null +++ b/requirements_bot copy.txt @@ -0,0 +1,21 @@ +setuptools +discord +yaach +t_dlp +spotify_dl +spotipy +openai +eyed3 +numpy +pdf2image +PyPDF2 +requests +spotipy +tiktoken +PyNaCl +flask[async] +waitress +clickupython +assemblyai[extras] +SpeechRecognition +git+https://github.com/imayhaveborkedit/discord-ext-voice-recvO \ No newline at end of file diff --git a/requirements_bot.txt b/requirements_bot.txt index dd2fcd4..2831a78 100644 --- a/requirements_bot.txt +++ b/requirements_bot.txt @@ -1,3 +1,4 @@ +setuptools discord yt_dlp spotify_dl @@ -11,9 +12,9 @@ requests spotipy tiktoken PyNaCl -flask +flask[async] waitress clickupython assemblyai[extras] SpeechRecognition -git+https://github.com/imayhaveborkedit/discord-ext-voice-recv \ No newline at end of file +git+https://github.com/imayhaveborkedit/discord-ext-voice-recvO \ No newline at end of file diff --git a/sr_example.py b/sr_example.py deleted file mode 100644 index 3c176cf..0000000 --- a/sr_example.py +++ /dev/null @@ -1,229 +0,0 @@ -# -*- coding: utf-8 -*- - -from __future__ import annotations - -import logging - -from discord.ext.voice_recv.sinks import AudioSink - -log = logging.getLogger(__name__) - -__all__ = [ - 'SpeechRecognitionSink', -] - -try: - import discord.ext.speech_recognition as sr # type: ignore -except ImportError: - - def SpeechRecognitionSink(**kwargs) -> AudioSink: - """A stub for when the SpeechRecognition module isn't found.""" - raise RuntimeError('The SpeechRecognition module is required to use this sink.') - -else: - import time - import array - import asyncio - import audioop - - from collections import defaultdict - - from discord.ext.voice_recv.sinks import SilencePacket - - from typing import TYPE_CHECKING, TypedDict - - if TYPE_CHECKING: - from concurrent.futures import Future as CFuture - from typing import Literal, Callable, Optional, Any, Final, Protocol, Awaitable, TypeVar - - from discord import Member - - from ..opus import VoiceData - from ..types import MemberOrUser as User - - T = TypeVar('T') - - SRRecognizerMethod = Literal[ - 'sphinx', - 'google', - 'google_cloud', - 'wit', - 'azure', - 'bing', - 'lex', - 'houndify', - 'amazon', - 'assemblyai', - 'ibm', - 'tensorflow', - 'whisper', - 'vosk', - ] - - class SRStopper(Protocol): - def __call__(self, wait: bool = True, /) -> None: - ... - - SRProcessDataCB = Callable[[sr.Recognizer, sr.AudioData, User], Optional[str]] - SRTextCB = Callable[[User, str], Any] - - class _StreamData(TypedDict): - stopper: Optional[SRStopper] - recognizer: sr.Recognizer - buffer: array.array[int] - - class SpeechRecognitionSink(AudioSink): # type: ignore - def __init__( - self, - *, - process_cb: Optional[SRProcessDataCB] = None, - text_cb: Optional[SRTextCB] = None, - default_recognizer: SRRecognizerMethod = 'assemblyai', - phrase_time_limit: int = 10, - ignore_silence_packets: bool = True, - ): - super().__init__(None) - self.process_cb: Optional[SRProcessDataCB] = process_cb - self.text_cb: Optional[SRTextCB] = text_cb - self.phrase_time_limmit: int = phrase_time_limit - self.ignore_silence_packets: bool = ignore_silence_packets - - self.default_recognizer: SRRecognizerMethod = default_recognizer - self._stream_data: defaultdict[int, _StreamData] = defaultdict( - lambda: _StreamData(stopper=None, recognizer=sr.Recognizer(), buffer=array.array('B')) - ) - - def _await(self, coro: Awaitable[T]) -> CFuture[T]: - assert self.client is not None - return asyncio.run_coroutine_threadsafe(coro, self.client.loop) - - def wants_opus(self) -> bool: - return False - - def write(self, user: Optional[User], data: VoiceData) -> None: - if self.ignore_silence_packets and isinstance(data.packet, SilencePacket): - return - - if user is None: - return - - sdata = self._stream_data[user.id] - sdata['buffer'].extend(data.pcm) - - if not sdata['stopper']: - sdata['stopper'] = sdata['recognizer'].listen_in_background( - DiscordSRAudioSource(sdata['buffer']), self.background_listener(user), self.phrase_time_limmit - ) - - def background_listener(self, user: User): - process_cb = self.process_cb or self.get_default_process_callback() - text_cb = self.text_cb or self.get_default_text_callback() - - def callback(_recognizer: sr.Recognizer, _audio: sr.AudioData): - output = process_cb(_recognizer, _audio, user) - if output is not None: - text_cb(user, output) - - return callback - - def get_default_process_callback(self) -> SRProcessDataCB: - def cb(recognizer: sr.Recognizer, audio: sr.AudioData, user: Optional[User]) -> Optional[str]: - log.debug("Got %s, %s, %s", audio, audio.sample_rate, audio.sample_width) - text: Optional[str] = None - try: - # they changed recognize_google to be optionally assigned at runtime... - func = getattr(recognizer, 'recognize_' + self.default_recognizer, recognizer.recognize_google) # type: ignore - text = func(audio) # type: ignore - except sr.UnknownValueError: - log.debug("Bad speech chunk") - # self._debug_audio_chunk(audio) - - return text - - return cb - - def get_default_text_callback(self) -> SRTextCB: - def cb(user: Optional[User], text: Optional[str]) -> Any: - log.info("%s said: %s", user.display_name if user else 'Someone', text) - - return cb - - @AudioSink.listener() - def on_voice_member_disconnect(self, member: Member, ssrc: Optional[int]) -> None: - self._drop(member.id) - - def cleanup(self) -> None: - for user_id in tuple(self._stream_data.keys()): - self._drop(user_id) - - def _drop(self, user_id: int) -> None: - data = self._stream_data.pop(user_id) - - stopper = data.get('stopper') - if stopper: - stopper() - - buffer = data.get('buffer') - if buffer: - # arrays don't have a clear function - del buffer[:] - - def _debug_audio_chunk(self, audio: sr.AudioData, filename: str = 'sound.wav') -> None: - import io, wave, discord - - with io.BytesIO() as b: - with wave.open(b, 'wb') as writer: - writer.setframerate(48000) - writer.setsampwidth(2) - writer.setnchannels(2) - writer.writeframes(audio.get_wav_data()) - - b.seek(0) - f = discord.File(b, filename) - self._await(self.voice_client.channel.send(file=f)) # type: ignore - - class DiscordSRAudioSource(sr.AudioSource): - little_endian: Final[bool] = True - SAMPLE_RATE: Final[int] = 48_000 - SAMPLE_WIDTH: Final[int] = 2 - CHANNELS: Final[int] = 2 - CHUNK: Final[int] = 960 - - def __init__(self, buffer: array.array[int]): - self.buffer = buffer - self._entered: bool = False - - @property - def stream(self): - return self - - def __enter__(self): - if self._entered: - log.warning('Already entered sr audio source') - self._entered = True - return self - - def __exit__(self, *exc) -> None: - self._entered = False - if any(exc): - log.exception('Error closing sr audio source') - - def read(self, size: int) -> bytes: - # TODO: make this timeout configurable - for _ in range(10): - if len(self.buffer) < size * self.CHANNELS: - time.sleep(0.1) - else: - break - else: - if len(self.buffer) == 0: - return b'' - - chunksize = size * self.CHANNELS - audiochunk = self.buffer[:chunksize].tobytes() - del self.buffer[: min(chunksize, len(audiochunk))] - audiochunk = audioop.tomono(audiochunk, 2, 1, 1) - return audiochunk - - def close(self) -> None: - self.buffer.clear() \ No newline at end of file diff --git a/stream_test.py b/stream_test.py index 82a410e..7b4411d 100644 --- a/stream_test.py +++ b/stream_test.py @@ -6,57 +6,62 @@ # # Note: Some macOS users might need to use `pip3` instead of `pip`. -import pyaudio import assemblyai as aai +import pyaudio aai.settings.api_key = "aa9962f0088a449a9c4ab2361e96cc08" -def on_open(session_opened: aai.RealtimeSessionOpened): - "This function is called when the connection has been established." - print("Session ID:", session_opened.session_id) +def on_open(session_opened: aai.RealtimeSessionOpened): + "This function is called when the connection has been established." + + print("Session ID:", session_opened.session_id) + def on_data(transcript: aai.RealtimeTranscript): - "This function is called when a new transcript has been received." + "This function is called when a new transcript has been received." - if not transcript.text: - return + if not transcript.text: + return + + if isinstance(transcript, aai.RealtimeFinalTranscript): + print(transcript.text, end="\r\n") + else: + print(transcript.text, end="\r") - if isinstance(transcript, aai.RealtimeFinalTranscript): - print(transcript.text, end="\r\n") - else: - print(transcript.text, end="\r") def on_error(error: aai.RealtimeError): - "This function is called when the connection has been closed." + "This function is called when the connection has been closed." + + print("An error occured:", error) - print("An error occured:", error) def on_close(): - "This function is called when the connection has been closed." + "This function is called when the connection has been closed." + + print("Closing Session") - print("Closing Session") transcriber = aai.RealtimeTranscriber( - on_data=on_data, - on_error=on_error, - sample_rate=44_100, - on_open=on_open, # optional - on_close=on_close, # optional + on_data=on_data, + on_error=on_error, + sample_rate=44_100, + on_open=on_open, # optional + on_close=on_close, # optional ) pa = pyaudio.PyAudio() for i in range(pa.get_device_count()): - print (pa.get_device_info_by_index(i)) + print(pa.get_device_info_by_index(i)) # Start the connection -#transcriber.connect() +# transcriber.connect() # Open a microphone stream -#microphone_stream = aai.extras.MicrophoneStream() +# microphone_stream = aai.extras.MicrophoneStream() # Press CTRL+C to abort -#transcriber.stream(microphone_stream) +# transcriber.stream(microphone_stream) -#transcriber.close() +# transcriber.close() diff --git a/test.py b/test.py new file mode 100644 index 0000000..357bb3f --- /dev/null +++ b/test.py @@ -0,0 +1,20 @@ +import logging +from logging import handlers + +logger = logging.getLogger("discord") +logger.setLevel(logging.DEBUG) +handler = handlers.RotatingFileHandler( + filename="test.log", + encoding="utf-8", + mode="a", + maxBytes=6 * 1024 * 1024, + backupCount=6, +) +formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s") +handler.setFormatter(formatter) +logger.addHandler(handler) + + +logger2 = logging.getLogger("discord") +for item in logger2.handlers: + print(item) diff --git a/test_data_retrieval.py b/test_data_retrieval.py deleted file mode 100644 index 32dd665..0000000 --- a/test_data_retrieval.py +++ /dev/null @@ -1,26 +0,0 @@ -""" -This Python code snippet is connecting to a MySQL database -using the `mysql.connector` library and fetching data from a table named `scimag` -Here is a breakdown of what the code is doing: -""" - -import netrc - -import mysql.connector - -NETRC_FILE = "/home/mtuszowski/.netrc" -netrc_mod = netrc.netrc(NETRC_FILE) -REMOTE_HOST_NAME = "192.168.1.192" -authTokens = netrc_mod.authenticators(REMOTE_HOST_NAME) - -mydb = mysql.connector.connect( - host=REMOTE_HOST_NAME, - user=authTokens[0], - password=authTokens[2], - database="scihubdois", -) -mycursor = mydb.cursor() - -mycursor.execute("SELECT * FROM scimag WHERE Title Like 'spider%'") -for x in mycursor: - print(x) diff --git a/test_time.py b/test_time.py index 63b1f06..0c71465 100644 --- a/test_time.py +++ b/test_time.py @@ -1,7 +1,8 @@ import time + first_time = time.time_ns() time.sleep(1) time_diff = time.time_ns() - first_time print(time_diff) -#2000149433 \ No newline at end of file +# 2000149433 diff --git a/thin_client.py b/thin_client.py new file mode 100644 index 0000000..aed2484 --- /dev/null +++ b/thin_client.py @@ -0,0 +1,92 @@ +# This Python file uses the following encoding: utf-8 +# trunk-ignore-all(bandit/B311) +# pylint: disable=line-too-long +# pylint: disable=too-many-lines +""" +Module of a python bot named Conjurer - used to work on BDSM discord servers. +""" +import logging + +# *=========================================== Standard Library Imports +import random +import threading +from logging import handlers + +# *==============Imported libraries +import discord +from discord.ext import commands + +from communication_subroutine import comm_subroutine +from constants import ENCODING, LOGFILE, TOKEN + +# *=========================================== 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, +) +formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s") +handler.setFormatter(formatter) +logger.addHandler(handler) +random.seed() +client = commands.Bot(intents=intents, command_prefix="$") + + +# *=========================================== Define Events +@client.event +async def on_ready(): + """Metoda wywoływana przy połączeniu do serwera.""" + logger.debug("%s has connected to Discord!", client.user) + # TODO: load vs reload + await client.load_extension("administration_commands") + + await client.load_extension("librarian_commands") + await client.load_extension("music_commands") + await client.load_extension("radio_commands") + + await client.load_extension("ai_commands") + + await client.load_extension("other_commands") + await client.load_extension("voice_recognition_commands") + + + logger.info(client.cogs) + await client.change_presence(activity=discord.Game(name="Axe Throwing Darts")) + await client.tree.sync() + for com in client.commands: + logger.info("Command %s is awejleble", com.qualified_name) + + +# TODO: ADMINISTRATION + + +# *================================== Run +if __name__ == "__main__": + logger.info("Starting discord bot") + threads = [] + logger.info("Starting discord bot: Creating threads") + threads.append(threading.Thread(target=client.run, args=(TOKEN,))) + threads.append(threading.Thread(target=comm_subroutine)) + logger.info("Starting discord bot: Starting threads") + WRK_CNT = 0 + for worker in threads: + WRK_CNT += 1 + logger.info("Starting discord bot: Starting thread %s", WRK_CNT) + worker.start() + logger.info("Starting discord bot: Joining threads") + WRK_CNT = 0 + for worker in threads: + WRK_CNT += 1 + logger.info("Starting discord bot: Joining thread %s", WRK_CNT) + worker.join() diff --git a/voice_example.py b/voice_example.py deleted file mode 100644 index 36cec22..0000000 --- a/voice_example.py +++ /dev/null @@ -1,47 +0,0 @@ -# -*- coding: utf-8 -*- - -import discord -from discord.ext import commands, voice_recv - -discord.opus._load_default() - -bot = commands.Bot(command_prefix=commands.when_mentioned, intents=discord.Intents.all()) - -class Testing(commands.Cog): - def __init__(self, bot): - self.bot = bot - - @commands.command() - async def test(self, ctx): - def callback(user, data: voice_recv.VoiceData): - print(f"Got packet from {user}") - - ## voice power level, how loud the user is speaking - # ext_data = packet.extension_data.get(voice_recv.ExtensionID.audio_power) - # value = int.from_bytes(ext_data, 'big') - # power = 127-(value & 127) - # print('#' * int(power * (79/128))) - ## instead of 79 you can use shutil.get_terminal_size().columns-1 - - vc = await ctx.author.voice.channel.connect(cls=voice_recv.VoiceRecvClient) - vc.listen(voice_recv.BasicSink(callback)) - - @commands.command() - async def stop(self, ctx): - await ctx.voice_client.disconnect() - - @commands.command() - async def die(self, ctx): - ctx.voice_client.stop() - await ctx.bot.close() - -@bot.event -async def on_ready(): - print('Logged in as {0.id}/{0}'.format(bot.user)) - print('------') - await bot.add_cog(Testing(bot)) - -REMOTE_HOST_NAME = "discord" - - -bot.run("NzUxNDQxODgzNDA2MDA4NDEw.Go--wb.Nr28Oo4eYAP1p2XFVHF5uIQfcPD7s_jO2NfMCQ") diff --git a/voice_recognition.py b/voice_recognition_commands.py similarity index 52% rename from voice_recognition.py rename to voice_recognition_commands.py index 73bdfb8..67b9be5 100644 --- a/voice_recognition.py +++ b/voice_recognition_commands.py @@ -1,49 +1,64 @@ -import logging -import wave import asyncio +import logging +import netrc +import time +import wave + import assemblyai as aai import discord -from discord.ext import commands, voice_recv, tasks +from discord.ext import commands, tasks, voice_recv from discord.opus import Decoder as OpusDecoder -import time + # Replace with your API key -aai.settings.api_key = "aa9962f0088a449a9c4ab2361e96cc08" +NETRC_FILE = "/home/pi/.netrc" +netrc_mod = netrc.netrc(NETRC_FILE) +authTokens = netrc_mod.authenticators("assemblyai") +aai.settings.api_key = authTokens[2] + discord.opus._load_default() CHANNELS = OpusDecoder.CHANNELS SAMPLE_WIDTH = OpusDecoder.SAMPLE_SIZE // OpusDecoder.CHANNELS SAMPLING_RATE = OpusDecoder.SAMPLING_RATE -#rotate file after there is 0.5s between last received pcm for user. -#delete messsages after user disconnect +# rotate file after there is 0.5s between last received pcm for user. +# delete messsages after user disconnect + +LOCATION = "/home/pi/Conjurer/transcripts/" -logger = logging.getLogger("discord") -location = "/home/pi/Conjurer/transcripts/" class CommunicationObject: def __init__(self, msg_type, user, data): + self.logger = logging.getLogger("discord") self.type = msg_type self.user = user self.data = data + def __repr__(self): return f"{self.type} : {self.user} : {self.data}" + class WaveWriter: - def __init__(self, user_id, queue): + def __init__(self, user_id, queue, location): self.queue = queue self.user = user_id self.username = str(user_id.id) - #here we can add hashing function to make transcription files not possible to be connected with discord id + self.location = location + # here we can add hashing function to make transcription files not possible to be connected with discord id self.present_file_id = 0 self.file_name_past = None - self.file_name_present = location + self.username + "_" + str(self.present_file_id) + ".mp3" - self.transcript_file_present : wave.Wave_write = wave.open( + self.file_name_present = ( + self.location + self.username + "_" + str(self.present_file_id) + ".mp3" + ) + self.transcript_file_present: wave.Wave_write = wave.open( self.file_name_present, "wb" ) self.transcript_file_present.setnchannels(CHANNELS) self.transcript_file_present.setsampwidth(SAMPLE_WIDTH) self.transcript_file_present.setframerate(SAMPLING_RATE) - self.file_name_future = location + self.username + "_" + str(self.present_file_id + 1) + ".mp3" - self.transcript_file_future : wave.Wave_write = wave.open( + self.file_name_future = ( + self.location + self.username + "_" + str(self.present_file_id + 1) + ".mp3" + ) + self.transcript_file_future: wave.Wave_write = wave.open( self.file_name_future, "wb" ) self.transcript_file_future.setnchannels(CHANNELS) @@ -60,14 +75,18 @@ class WaveWriter: self.present_file_id += 1 self.file_name_present = self.file_name_future self.transcript_file_present = self.transcript_file_future - self.file_name_future = location + self.username + "_" + str(self.present_file_id + 1) + ".mp3" - self.transcript_file_future : wave.Wave_write = wave.open( + self.file_name_future = ( + self.location + self.username + "_" + str(self.present_file_id + 1) + ".mp3" + ) + self.transcript_file_future: wave.Wave_write = wave.open( self.file_name_future, "wb" ) self.transcript_file_future.setnchannels(CHANNELS) self.transcript_file_future.setsampwidth(SAMPLE_WIDTH) self.transcript_file_future.setframerate(SAMPLING_RATE) - operation = CommunicationObject(msg_type="send_file",user=self.user,data=[self.file_name_past]) + operation = CommunicationObject( + msg_type="send_file", user=self.user, data=[self.file_name_past] + ) await self.queue.put(operation) @@ -75,7 +94,7 @@ class WaveWriter: self.transcript_file_present.writeframes(pcmdata) def cleanup(self): - logger.info("Cleanup for user %s", self.username) + self.logger.info("Cleanup for user %s", self.username) self.transcript_file_present.close() self.transcript_file_future.close() @@ -84,17 +103,26 @@ class SRBuffer(voice_recv.AudioSink): """Endpoint AudioSink that generates a wav file. Best used in conjunction with a silence generating sink. (TBD) """ + # on member join dodajemytypa do listy # on member disconnect - dropujemy go - def __init__(self, queue): + def __init__(self, queue, location): super().__init__() self.queue = queue self.wavewriter = {} + self.logger = logging.getLogger("discord") + self.location = location def on_user_connect(self, username): - self.wavewriter[str(username.id)] = [WaveWriter(username, self.queue), time.time_ns(), time.time_ns(), False, False] + self.wavewriter[str(username.id)] = [ + WaveWriter(username, self.queue, self.location), + time.time_ns(), + time.time_ns(), + False, + False, + ] - def on_user_disconnect(self,username): + def on_user_disconnect(self, username): self.wavewriter[str(username.id)].cleanup() self.wavewriter.pop(str(username.id)) @@ -102,21 +130,23 @@ class SRBuffer(voice_recv.AudioSink): return False def write(self, user, data) -> None: - #logger.info("DAta write") + # logger.info("DAta write") if user: self.wavewriter[str(user.id)][0].writeframes(data.pcm) - self.wavewriter[str(user.id)][1] = time.time_ns() #time from last write - self.wavewriter[str(user.id)][3] = True #data written in last iter - self.wavewriter[str(user.id)][4] = True #data in buff + self.wavewriter[str(user.id)][1] = time.time_ns() # time from last write + self.wavewriter[str(user.id)][3] = True # data written in last iter + self.wavewriter[str(user.id)][4] = True # data in buff time.sleep(0.001) def cleanup(self) -> None: try: - logger.info("Cleanup for SRBuffer") + self.logger.info("Cleanup for SRBuffer") for item in self.wavewriter.values(): item[0].cleanup() except Exception: - logger.warning("WaveSink got error closing file on cleanup", exc_info=True) + self.logger.warning( + "WaveSink got error closing file on cleanup", exc_info=True + ) class Transcriber(commands.Cog): @@ -124,41 +154,53 @@ class Transcriber(commands.Cog): self.bot = bot self.threads = [] self.comm_queue = asyncio.Queue() - self.wsink = SRBuffer(self.comm_queue) + self.wsink = SRBuffer(self.comm_queue, LOCATION) self.worker = None self.mc = None self.vc = None + self.logger = logging.getLogger("discord") @commands.hybrid_command(name="transcribe") async def test(self, ctx): if self.vc: - vc = self.vc #to juz powinien byc voice channel z funkcja conenct + vc = self.vc # to juz powinien byc voice channel z funkcja conenct else: vc = None self.mc = ctx.message.channel if self.bot.voice_clients: - if isinstance(self.bot.voice_clients[0], voice_recv.VoiceRecvClient): - logger.debug("Already transcribing") + if isinstance(self.bot.voice_clients[0], voice_recv.VoiceRecvClient): + self.logger.debug("Already transcribing") else: - logger.debug("Already connected with other client") + self.logger.debug("Already connected with other client") else: - logger.debug("Connected") + self.logger.debug("Connected") vc = await ctx.author.voice.channel.connect(cls=voice_recv.VoiceRecvClient) - logger.info(self.bot.voice_clients) + self.logger.info(self.bot.voice_clients) self.check_data.start() self.worker = asyncio.create_task(self.transcribe_output_queue()) vc.listen(self.wsink) - @tasks.loop(seconds=0.5) async def check_data(self): for item in self.wsink.wavewriter.values(): if not item[3]: timediff_rotation = time.time_ns() - item[2] - timediff_write = time.time_ns() -item[1] - if timediff_rotation > 13000149433 and timediff_write > 500014943 and item[4]: - logger.info("File rotation time since last write %s %s", timediff_write, timediff_write/1e9) - logger.info("File rotation time since last rotation %s %s",timediff_rotation, timediff_rotation/1e9) + timediff_write = time.time_ns() - item[1] + if ( + timediff_rotation > 13000149433 + and timediff_write > 500014943 + and item[4] + ): + self.logger.info( + "File rotation time since last write %s %s", + timediff_write, + timediff_write / 1e9, + ) + self.logger.info( + "File rotation time since last rotation %s %s", + timediff_rotation, + timediff_rotation / 1e9, + ) item[2] = time.time_ns() item[4] = False await item[0].rotate() @@ -167,67 +209,71 @@ class Transcriber(commands.Cog): @commands.Cog.listener() async def on_voice_state_update(self, user, before, after): if user == self.bot.user: - logger.debug("Ignoring self") + self.logger.debug("Ignoring self") return if before.channel is None: - logger.info("User %s connected to channel %s", user, after.channel.name) + self.logger.info( + "User %s connected to channel %s", user, after.channel.name + ) self.wsink.on_user_connect(user) - elif after.channel is None: - logger.info("User %s disconnected from channel %s", user, before.channel.name) - operation = CommunicationObject(msg_type="user_cleanup", user=user, data=None) + elif after.channel is None: + self.logger.info( + "User %s disconnected from channel %s", user, before.channel.name + ) + operation = CommunicationObject( + msg_type="user_cleanup", user=user, data=None + ) await self.comm_queue.put(operation) else: - logger.debug("User VC status changed %s", user.id) - logger.debug("Before %s", before) - logger.debug("After %s", after) - + self.logger.debug("User VC status changed %s", user.id) + self.logger.debug("Before %s", before) + self.logger.debug("After %s", after) @commands.command(name="stop_transcribe") async def stop(self, ctx): self.check_data.stop() - stop_token = CommunicationObject("STOP",None,None) + stop_token = CommunicationObject("STOP", None, None) await self.comm_queue.put(stop_token) await ctx.voice_client.disconnect() async def transcribe_output_queue(self): - logger.info("Transcript uploader start") + self.logger.info("Transcript uploader start") config = aai.TranscriptionConfig(language_code="pl") transcriber = aai.Transcriber() - logger.debug("Transcriber queue id: %s",id(self.comm_queue)) + self.logger.debug("Transcriber queue id: %s", id(self.comm_queue)) while True: - logger.debug("waiting for tasks") + self.logger.debug("waiting for tasks") item = await self.comm_queue.get() - logger.debug("Got %s", item) + self.logger.debug("Got %s", item) if "STOP" in item.type: - logger.debug("Queue ended") + self.logger.debug("Queue ended") break elif "send_file" in item.type: - logger.debug("Sending file for transcription") + self.logger.debug("Sending file for transcription") transcript = None for iter in item.data: try: coro = asyncio.to_thread( - transcriber.transcribe, - iter, - config=config + transcriber.transcribe, iter, config=config ) transcript = await coro except Exception as e: - logger.warn("Exceptiom occured %s", e) + self.logger.warn("Exceptiom occured %s", e) await self.mc.send(f"{item.user} : {transcript.text}") if transcript.error: - logger.error(transcript.error) + self.logger.error(transcript.error) raise AssertionError elif "user_cleanup" in item.type: - logger.info("User %s disconnected - cleanup action") + self.logger.info("User %s disconnected - cleanup action") else: - logger.warn("Something went wrong with object %s", item) - logger.info("Transcript uploader stoped") + self.logger.warn("Something went wrong with object %s", item) + self.logger.info("Transcript uploader stoped") + async def setup(bot): logger = logging.getLogger("discord") await bot.add_cog(Transcriber(bot)) - logger.info("Loading voice transcribed module done") + logger.info("Loading voice transcriber module done")