1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
|
import calendar
import json
import logging
import random
from datetime import datetime
from pathlib import Path
from typing import Tuple, Union
import discord
from discord.ext import commands
from bot.constants import Colours
log = logging.getLogger(__name__)
LETTER_EMOJI = ':love_letter:'
HEART_EMOJIS = [":heart:", ":gift_heart:", ":revolving_hearts:", ":sparkling_heart:", ":two_hearts:"]
class ValentineZodiac(commands.Cog):
"""A Cog that returns a counter compatible zodiac sign to the given user's zodiac sign."""
def __init__(self, bot: commands.Bot):
self.bot = bot
self.zodiacs, self.zodiac_fact = self.load_comp_json()
@staticmethod
def load_comp_json() -> Tuple[dict, dict]:
"""Load zodiac compatibility from static JSON resource."""
explanation_file = Path("bot/resources/valentines/zodiac_explanation.json")
compatibility_file = Path("bot/resources/valentines/zodiac_compatibility.json")
with explanation_file.open(encoding="utf8") as json_data:
zodiac_fact = json.load(json_data)
for zodiac_data in zodiac_fact.values():
zodiac_data['start_at'] = datetime.fromisoformat(zodiac_data['start_at'])
zodiac_data['end_at'] = datetime.fromisoformat(zodiac_data['end_at'])
with compatibility_file.open(encoding="utf8") as json_data:
zodiacs = json.load(json_data)
return zodiacs, zodiac_fact
def generate_invalidname_embed(self, zodiac: str) -> discord.Embed:
"""Returns error embed."""
embed = discord.Embed()
embed.color = Colours.soft_red
error_msg = f"**{zodiac}** is not a valid zodiac sign, here is the list of valid zodiac signs.\n"
names = list(self.zodiac_fact)
middle_index = len(names) // 2
first_half_names = ", ".join(names[:middle_index])
second_half_names = ", ".join(names[middle_index:])
embed.description = error_msg + first_half_names + ",\n" + second_half_names
log.info("Invalid zodiac name provided.")
return embed
def zodiac_build_embed(self, zodiac: str) -> discord.Embed:
"""Gives informative zodiac embed."""
zodiac = zodiac.capitalize()
embed = discord.Embed()
embed.color = Colours.pink
if zodiac in self.zodiac_fact:
log.trace("Making zodiac embed.")
embed.title = f"__{zodiac}__"
embed.description = self.zodiac_fact[zodiac]["About"]
embed.add_field(name='__Motto__', value=self.zodiac_fact[zodiac]["Motto"], inline=False)
embed.add_field(name='__Strengths__', value=self.zodiac_fact[zodiac]["Strengths"], inline=False)
embed.add_field(name='__Weaknesses__', value=self.zodiac_fact[zodiac]["Weaknesses"], inline=False)
embed.add_field(name='__Full form__', value=self.zodiac_fact[zodiac]["full_form"], inline=False)
embed.set_thumbnail(url=self.zodiac_fact[zodiac]["url"])
else:
embed = self.generate_invalidname_embed(zodiac)
log.trace("Successfully created zodiac information embed.")
return embed
def zodiac_date_verifier(self, query_date: datetime) -> str:
"""Returns zodiac sign by checking date."""
for zodiac_name, zodiac_data in self.zodiac_fact.items():
if zodiac_data["start_at"].date() <= query_date.date() <= zodiac_data["end_at"].date():
log.trace("Zodiac name sent.")
return zodiac_name
@commands.group(name='zodiac', invoke_without_command=True)
async def zodiac(self, ctx: commands.Context, zodiac_sign: str) -> None:
"""Provides information about zodiac sign by taking zodiac sign name as input."""
final_embed = self.zodiac_build_embed(zodiac_sign)
await ctx.send(embed=final_embed)
log.trace("Embed successfully sent.")
@zodiac.command(name="date")
async def date_and_month(self, ctx: commands.Context, date: int, month: Union[int, str]) -> None:
"""Provides information about zodiac sign by taking month and date as input."""
if isinstance(month, str):
month = month.capitalize()
try:
month = list(calendar.month_abbr).index(month[:3])
log.trace('Valid month name entered by user')
except ValueError:
log.info('Invalid month name entered by user')
await ctx.send(f"Sorry, but `{month}` is not a valid month name.")
return
if (month == 1 and 1 <= date <= 19) or (month == 12 and 22 <= date <= 31):
zodiac = "capricorn"
final_embed = self.zodiac_build_embed(zodiac)
else:
try:
zodiac_sign_based_on_date = self.zodiac_date_verifier(datetime(2020, month, date))
log.trace("zodiac sign based on month and date received.")
except ValueError as e:
final_embed = discord.Embed()
final_embed.color = Colours.soft_red
final_embed.description = f"Zodiac sign could not be found because.\n```{e}```"
log.info(f'Error in "zodiac date" command:\n{e}.')
else:
final_embed = self.zodiac_build_embed(zodiac_sign_based_on_date)
await ctx.send(embed=final_embed)
log.trace("Embed from date successfully sent.")
@zodiac.command(name="partnerzodiac", aliases=['partner'])
async def partner_zodiac(self, ctx: commands.Context, zodiac_sign: str) -> None:
"""Provides a random counter compatible zodiac sign to the given user's zodiac sign."""
embed = discord.Embed()
embed.color = Colours.pink
zodiac_check = self.zodiacs.get(zodiac_sign.capitalize())
if zodiac_check:
compatible_zodiac = random.choice(self.zodiacs[zodiac_sign.capitalize()])
emoji1 = random.choice(HEART_EMOJIS)
emoji2 = random.choice(HEART_EMOJIS)
embed.title = "Zodiac Compatibility"
embed.description = (
f'{zodiac_sign.capitalize()}{emoji1}{compatible_zodiac["Zodiac"]}\n'
f'{emoji2}Compatibility meter : {compatible_zodiac["compatibility_score"]}{emoji2}'
)
embed.add_field(
name=f'A letter from Dr.Zodiac {LETTER_EMOJI}',
value=compatible_zodiac['description']
)
else:
embed = self.generate_invalidname_embed(zodiac_sign)
await ctx.send(embed=embed)
log.trace("Embed from date successfully sent.")
def setup(bot: commands.Bot) -> None:
"""Valentine zodiac Cog load."""
bot.add_cog(ValentineZodiac(bot))
|