2024-02-01 17:14:06 -05:00
# _____ _
# / ____| (_)
# | (___ ___ __ _ _____ ___ _ __ ___ _ __ ___ ___ _ __
# \___ \ / _ \/ _` / __\ \ /\ / / | '_ ` _ \| '_ ` _ \ / _ \ '__|
# ____) | __/ (_| \__ \\ V V /| | | | | | | | | | | | __/ |
# |_____/ \___|\__,_|___/ \_/\_/ |_|_| |_| |_|_| |_| |_|\___|_|
2024-02-01 18:39:10 -05:00
import random
2025-01-26 00:39:09 +00:00
from asyncio import create_task
2024-04-06 06:15:00 -04:00
from io import BytesIO
2024-02-01 17:14:06 -05:00
2024-02-01 18:39:10 -05:00
import aiohttp
2024-04-06 06:15:00 -04:00
import numpy as np
from discord import Colour , Embed , File
from PIL import Image
2024-03-07 03:38:34 -05:00
from red_commons . logging import getLogger
2024-04-06 06:15:00 -04:00
from redbot . core import Config , commands , data_manager
2024-02-01 17:14:06 -05:00
from redbot . core . bot import Red
2024-08-27 14:22:19 -04:00
from redbot . core . utils . chat_formatting import bold , error , humanize_list
2024-02-01 17:14:06 -05:00
2024-02-01 19:32:11 -05:00
import bible . errors
2024-02-02 12:43:09 -05:00
from bible . models import Version
2024-02-01 19:10:05 -05:00
2024-02-01 18:39:10 -05:00
2024-02-01 17:14:06 -05:00
class Bible ( commands . Cog ) :
""" Retrieve Bible verses from the API.bible API. """
2024-08-27 14:22:19 -04:00
__author__ = [ " [cswimr](https://www.coastalcommits.com/cswimr) " ]
__git__ = " https://www.coastalcommits.com/cswimr/SeaCogs "
2025-01-26 00:39:09 +00:00
__version__ = " 1.1.2 "
2024-08-27 14:22:19 -04:00
__documentation__ = " https://seacogs.coastalcommits.com/pterodactyl/ "
2024-02-01 17:14:06 -05:00
def __init__ ( self , bot : Red ) :
super ( ) . __init__ ( )
self . bot = bot
2024-02-01 17:50:35 -05:00
self . session = aiohttp . ClientSession ( )
2025-01-26 00:39:09 +00:00
self . config = Config . get_conf ( self , identifier = 481923957134912 , force_registration = True )
2024-04-08 05:55:35 -04:00
self . logger = getLogger ( " red.SeaCogs.Bible " )
2024-02-01 21:01:54 -05:00
self . config . register_global ( bible = " de4e12af7f28f599-02 " )
2024-02-01 17:50:35 -05:00
self . config . register_user ( bible = None )
2025-01-26 00:46:21 +00:00
async def cog_unload ( self ) :
2025-01-26 00:39:09 +00:00
create_task ( self . session . close ( ) )
2024-03-07 03:38:34 -05:00
def format_help_for_context ( self , ctx : commands . Context ) - > str :
pre_processed = super ( ) . format_help_for_context ( ctx ) or " "
n = " \n " if " \n \n " not in pre_processed else " "
text = [
f " { pre_processed } { n } " ,
2024-08-27 14:22:19 -04:00
f " { bold ( ' Cog Version: ' ) } [ { self . __version__ } ]( { self . __git__ } ) " ,
f " { bold ( ' Author: ' ) } { humanize_list ( self . __author__ ) } " ,
f " { bold ( ' Documentation: ' ) } { self . __documentation__ } " ,
2024-03-07 03:38:34 -05:00
]
return " \n " . join ( text )
2024-04-06 06:15:00 -04:00
def get_icon ( self , color : Colour ) - > File :
""" Get the docs.api.bible favicon with a given color. """
image_path = data_manager . bundled_data_path ( self ) / " api.bible-logo.png "
image = Image . open ( image_path )
image = image . convert ( " RGBA " )
data = np . array ( image )
2025-01-26 00:39:09 +00:00
red , green , blue , alpha = data . T # pylint: disable=unused-variable
2024-04-06 06:15:00 -04:00
white_areas = ( red == 255 ) & ( blue == 255 ) & ( green == 255 )
data [ . . . , : - 1 ] [ white_areas . T ] = color . to_rgb ( )
image = Image . fromarray ( data )
with BytesIO ( ) as image_binary :
image . save ( image_binary , " PNG " )
image_binary . seek ( 0 )
return File ( image_binary , filename = " icon.png " , description = " API.Bible Icon " )
2024-02-02 01:50:31 -05:00
async def translate_book_name ( self , bible_id : str , book_name : str ) - > str :
2024-02-01 17:50:35 -05:00
""" Translate a book name to a book ID. """
2025-01-26 00:39:09 +00:00
book_name_list = [ w . lower ( ) if w . lower ( ) == " of " else w . title ( ) for w in book_name . split ( ) ]
2024-02-01 20:08:27 -05:00
book_name = " " . join ( book_name_list )
2024-02-02 01:50:31 -05:00
books = await self . _get_books ( bible_id )
2024-02-01 17:50:35 -05:00
for book in books :
2024-02-01 18:58:52 -05:00
if book_name in ( book [ " abbreviation " ] , book [ " name " ] ) :
2024-02-01 18:39:10 -05:00
return book [ " id " ]
2024-02-01 19:46:39 -05:00
raise ValueError ( error ( f " Book { book_name } not found. " ) )
2024-02-01 17:50:35 -05:00
2024-02-02 12:43:09 -05:00
async def get_version ( self , bible_id : str ) - > Version :
""" Retrieve the version of the Bible being used. """
url = f " https://api.scripture.api.bible/v1/bibles/ { bible_id } "
headers = await self . bot . get_shared_api_tokens ( " api.bible " )
async with self . session . get ( url , headers = headers ) as response :
data = await response . json ( )
self . logger . debug (
" get_version executed with a response code of: %s " ,
response . status ,
)
if response . status == 401 :
raise bible . errors . Unauthorized ( )
if response . status == 403 :
raise bible . errors . BibleAccessError ( )
if response . status == 503 :
raise bible . errors . ServiceUnavailable ( )
return Version (
2024-02-02 12:55:19 -05:00
bible_id ,
2024-02-02 12:43:09 -05:00
data [ " data " ] [ " abbreviation " ] ,
2024-02-02 12:44:22 -05:00
data [ " data " ] [ " language " ] [ " name " ] ,
2024-02-02 12:43:09 -05:00
data [ " data " ] [ " abbreviationLocal " ] ,
2024-02-02 12:44:22 -05:00
data [ " data " ] [ " language " ] [ " nameLocal " ] ,
2024-02-02 13:09:46 -05:00
data [ " data " ] [ " description " ] ,
data [ " data " ] [ " descriptionLocal " ] ,
2024-02-02 12:43:09 -05:00
data [ " data " ] [ " copyright " ] ,
)
2024-02-01 19:10:05 -05:00
async def _get_passage (
2024-02-02 01:35:43 -05:00
self ,
ctx : commands . Context ,
bible_id : str ,
passage_id : str ,
include_verse_numbers : bool ,
2024-02-01 19:10:05 -05:00
) - > dict :
2024-02-01 17:50:35 -05:00
""" Get a Bible passage from the API.bible API. """
2024-02-01 19:10:05 -05:00
url = f " https://api.scripture.api.bible/v1/bibles/ { bible_id } /passages/ { passage_id } "
2024-02-01 17:52:45 -05:00
headers = await self . bot . get_shared_api_tokens ( " api.bible " )
2024-02-01 19:10:05 -05:00
params = {
2024-02-02 01:45:51 -05:00
" fums-version " : " 3 " ,
2024-02-01 19:10:05 -05:00
" content-type " : " text " ,
2024-02-01 19:11:11 -05:00
" include-notes " : " false " ,
" include-titles " : " false " ,
" include-chapter-numbers " : " false " ,
" include-verse-numbers " : str ( include_verse_numbers ) . lower ( ) ,
" include-verse-spans " : " false " ,
" use-org-id " : " false " ,
2024-02-01 19:10:05 -05:00
}
async with self . session . get ( url , headers = headers , params = params ) as response :
2024-02-01 20:17:44 -05:00
data = await response . json ( )
2024-02-01 19:10:05 -05:00
self . logger . debug (
2024-02-02 02:00:54 -05:00
" _get_passage executed with a response code of: %s " ,
2024-02-01 20:17:44 -05:00
response . status ,
2024-02-01 19:10:05 -05:00
)
2024-02-02 02:10:06 -05:00
if response . status == 400 :
raise bible . errors . InexplicableError ( )
2024-02-01 19:10:05 -05:00
if response . status == 401 :
2024-02-01 19:46:39 -05:00
raise bible . errors . Unauthorized ( )
2024-02-01 19:10:05 -05:00
if response . status == 403 :
2024-02-01 19:46:39 -05:00
raise bible . errors . BibleAccessError ( )
2024-02-01 19:25:02 -05:00
if response . status == 404 :
2024-02-01 19:46:39 -05:00
raise bible . errors . NotFound ( )
2024-02-02 00:05:36 -05:00
if response . status == 503 :
raise bible . errors . ServiceUnavailable ( )
2024-02-01 17:50:35 -05:00
2024-02-02 01:35:43 -05:00
fums_url = " https://fums.api.bible/f3 "
fums_params = {
" t " : data [ " meta " ] [ " fumsToken " ] ,
2024-02-02 02:00:18 -05:00
" dId " : self . bot . user . id ,
" sId " : ctx . message . created_at . timestamp ( ) ,
2024-02-02 02:07:21 -05:00
" uId " : hash ( str ( ctx . author . id ) ) ,
2024-02-02 01:35:43 -05:00
}
async with self . session . get ( fums_url , params = fums_params ) as response :
self . logger . debug (
2024-02-02 02:05:24 -05:00
" _get_passage FUMS executed with a response code of: %s \n Device ID: %s \n Session ID: %s \n User ID: %s ( %s ) " ,
2024-02-02 01:35:43 -05:00
response . status ,
2024-02-02 02:00:18 -05:00
self . bot . user . id ,
ctx . message . created_at . timestamp ( ) ,
2024-02-02 02:07:21 -05:00
hash ( str ( ctx . author . id ) ) ,
2024-02-02 02:00:18 -05:00
ctx . author . id ,
2024-02-02 01:35:43 -05:00
)
return data [ " data " ]
2024-02-02 01:50:31 -05:00
async def _get_books ( self , bible_id : str ) - > dict :
2024-02-01 17:50:35 -05:00
""" Get the books of the Bible from the API.bible API. """
url = f " https://api.scripture.api.bible/v1/bibles/ { bible_id } /books "
2024-02-01 17:52:45 -05:00
headers = await self . bot . get_shared_api_tokens ( " api.bible " )
2024-02-01 19:10:05 -05:00
2024-02-02 01:48:58 -05:00
async with self . session . get ( url , headers = headers ) as response :
2024-02-01 20:17:44 -05:00
data = await response . json ( )
2024-02-01 19:10:05 -05:00
self . logger . debug (
2024-02-02 02:00:54 -05:00
" _get_books executed with a response code of: %s " ,
2024-02-01 20:17:44 -05:00
response . status ,
2024-02-01 19:10:05 -05:00
)
if response . status == 401 :
2024-02-01 19:46:39 -05:00
raise bible . errors . Unauthorized ( )
2024-02-01 19:10:05 -05:00
if response . status == 403 :
2024-02-01 19:46:39 -05:00
raise bible . errors . BibleAccessError ( )
2024-02-02 00:05:36 -05:00
if response . status == 503 :
raise bible . errors . ServiceUnavailable ( )
2024-02-02 01:48:58 -05:00
return data [ " data " ]
2024-02-02 01:35:43 -05:00
2024-02-02 01:50:31 -05:00
async def _get_chapters ( self , bible_id : str , book_id : str ) - > dict :
2024-02-01 18:39:10 -05:00
""" Get the chapters of a book from the API.bible API. """
url = f " https://api.scripture.api.bible/v1/bibles/ { bible_id } /books/ { book_id } /chapters "
headers = await self . bot . get_shared_api_tokens ( " api.bible " )
2024-02-01 19:10:05 -05:00
2024-02-02 01:50:31 -05:00
async with self . session . get ( url , headers = headers ) as response :
2024-02-01 20:17:44 -05:00
data = await response . json ( )
2024-02-01 19:10:05 -05:00
self . logger . debug (
2024-02-02 02:00:54 -05:00
" _get_chapters executed with a response code of: %s " ,
2024-02-01 20:17:44 -05:00
response . status ,
2024-02-01 19:10:05 -05:00
)
if response . status == 401 :
2024-02-01 19:46:39 -05:00
raise bible . errors . Unauthorized ( )
2024-02-01 19:10:05 -05:00
if response . status == 403 :
2024-02-01 19:46:39 -05:00
raise bible . errors . BibleAccessError ( )
2024-02-02 00:05:36 -05:00
if response . status == 503 :
raise bible . errors . ServiceUnavailable ( )
2024-02-02 01:50:31 -05:00
return data [ " data " ]
2024-02-02 01:35:43 -05:00
2024-02-02 01:51:47 -05:00
async def _get_verses ( self , bible_id : str , book_id : str , chapter : int ) - > dict :
2024-02-01 18:39:10 -05:00
""" Get the verses of a chapter from the API.bible API. """
2024-02-01 18:46:59 -05:00
url = f " https://api.scripture.api.bible/v1/bibles/ { bible_id } /chapters/ { book_id } . { chapter } /verses "
2024-02-01 18:39:10 -05:00
headers = await self . bot . get_shared_api_tokens ( " api.bible " )
2024-02-01 19:10:05 -05:00
2024-02-02 01:51:47 -05:00
async with self . session . get ( url , headers = headers ) as response :
2024-02-01 20:17:44 -05:00
data = await response . json ( )
2024-02-01 19:10:05 -05:00
self . logger . debug (
2024-02-02 02:00:54 -05:00
" _get_verses executed with a response code of: %s " ,
2024-02-01 20:17:44 -05:00
response . status ,
2024-02-01 19:10:05 -05:00
)
if response . status == 401 :
2024-02-01 19:46:39 -05:00
raise bible . errors . Unauthorized ( )
2024-02-01 19:10:05 -05:00
if response . status == 403 :
2024-02-01 19:46:39 -05:00
raise bible . errors . BibleAccessError ( )
2024-02-02 00:05:36 -05:00
if response . status == 503 :
raise bible . errors . ServiceUnavailable ( )
2024-02-02 01:51:47 -05:00
return data [ " data " ]
2024-02-01 18:39:10 -05:00
2024-02-01 17:51:15 -05:00
@commands.group ( autohelp = True )
2024-02-01 18:48:20 -05:00
async def bible ( self , ctx : commands . Context ) :
""" Retrieve Bible verses from the API.bible API. """
@bible.command ( name = " passage " , aliases = [ " verse " ] )
async def bible_passage ( self , ctx : commands . Context , book : str , passage : str ) :
2024-02-01 18:14:42 -05:00
""" Get a Bible passage.
Example usage :
2024-02-01 18:49:06 -05:00
` [ p ] bible passage Genesis 1 : 1 `
` [ p ] bible passage John 3 : 16 - 3 : 17 ` """
2024-02-01 18:14:42 -05:00
bible_id = await self . config . bible ( )
2024-02-01 18:20:48 -05:00
2024-02-01 18:14:42 -05:00
try :
2024-02-02 01:50:31 -05:00
book_id = await self . translate_book_name ( bible_id , book )
2024-02-01 18:14:42 -05:00
except ValueError as e :
await ctx . send ( str ( e ) )
return
2024-02-01 18:20:48 -05:00
2024-02-01 19:46:39 -05:00
try :
2024-02-02 12:43:09 -05:00
version = await self . get_version ( bible_id )
2024-02-01 19:46:39 -05:00
if len ( passage . split ( " - " ) ) == 2 :
from_verse , to_verse = passage . replace ( " : " , " . " ) . split ( " - " )
if " . " not in to_verse :
to_verse = f " { from_verse . split ( ' . ' ) [ 0 ] } . { to_verse } "
2025-01-26 00:39:09 +00:00
passage = await self . _get_passage ( ctx , bible_id , f " { book_id } . { from_verse } - { book_id } . { to_verse } " , True )
2024-02-01 19:46:39 -05:00
else :
2025-01-26 00:39:09 +00:00
passage = await self . _get_passage ( ctx , bible_id , f " { book_id } . { passage . replace ( ' : ' , ' . ' ) } " , False )
2024-02-01 19:46:39 -05:00
except (
bible . errors . BibleAccessError ,
bible . errors . NotFound ,
2024-02-02 02:10:06 -05:00
bible . errors . InexplicableError ,
2024-02-02 00:05:36 -05:00
bible . errors . ServiceUnavailable ,
2024-02-01 19:46:39 -05:00
bible . errors . Unauthorized ,
) as e :
await ctx . send ( e . message )
return
2024-02-01 18:20:48 -05:00
2024-02-01 18:30:57 -05:00
if len ( passage [ " content " ] ) > 4096 :
await ctx . send ( " The passage is too long to send. " )
return
2024-02-01 21:09:53 -05:00
if await ctx . embed_requested ( ) :
2024-04-06 06:18:16 -04:00
icon = self . get_icon ( await ctx . embed_color ( ) )
2024-02-01 21:09:53 -05:00
embed = Embed (
title = f " { passage [ ' reference ' ] } " ,
description = passage [ " content " ] . replace ( " ¶ " , " " ) ,
2024-04-06 06:16:41 -04:00
color = await ctx . embed_color ( ) ,
2024-02-01 21:09:53 -05:00
)
2025-01-26 00:39:09 +00:00
embed . set_footer ( text = f " { ctx . prefix } bible passage - Powered by API.Bible - { version . abbreviationLocal } ( { version . languageLocal } , { version . descriptionLocal } ) " , icon_url = " attachment://icon.png " )
2024-04-06 06:15:00 -04:00
await ctx . send ( embed = embed , file = icon )
2024-02-01 21:09:53 -05:00
else :
await ctx . send ( f " ## { passage [ ' reference ' ] } \n { passage [ ' content ' ] } " )
2024-02-01 18:39:10 -05:00
@bible.command ( name = " random " )
async def bible_random ( self , ctx : commands . Context ) :
""" Get a random Bible verse. """
bible_id = await self . config . bible ( )
2024-02-01 19:10:05 -05:00
2024-02-01 19:46:39 -05:00
try :
2024-02-02 12:43:09 -05:00
version = await self . get_version ( bible_id )
2024-02-02 01:50:31 -05:00
books = await self . _get_books ( bible_id )
2024-02-01 19:46:39 -05:00
book = random . choice ( books )
2024-02-02 01:50:31 -05:00
chapters = await self . _get_chapters ( bible_id , book [ " id " ] )
2024-02-01 19:46:39 -05:00
chapter = random . choice ( chapters )
2024-02-02 01:51:47 -05:00
verses = await self . _get_verses ( bible_id , book [ " id " ] , chapter [ " number " ] )
2024-02-01 19:46:39 -05:00
verse = random . choice ( verses ) [ " id " ]
2024-02-02 01:35:43 -05:00
passage = await self . _get_passage ( ctx , bible_id , verse , False )
2024-02-01 19:46:39 -05:00
except (
bible . errors . BibleAccessError ,
bible . errors . NotFound ,
2024-02-02 02:10:06 -05:00
bible . errors . InexplicableError ,
2024-02-02 00:05:36 -05:00
bible . errors . ServiceUnavailable ,
2024-02-01 19:46:39 -05:00
bible . errors . Unauthorized ,
) as e :
await ctx . send ( e . message )
return
2024-02-01 19:10:05 -05:00
2024-02-01 21:09:53 -05:00
if await ctx . embed_requested ( ) :
2024-04-06 06:18:16 -04:00
icon = self . get_icon ( await ctx . embed_color ( ) )
2024-02-01 21:09:53 -05:00
embed = Embed (
title = f " { passage [ ' reference ' ] } " ,
description = passage [ " content " ] . replace ( " ¶ " , " " ) ,
2024-04-06 06:16:41 -04:00
color = await ctx . embed_color ( ) ,
2024-02-01 21:09:53 -05:00
)
2025-01-26 00:39:09 +00:00
embed . set_footer ( text = f " { ctx . prefix } bible random - Powered by API.Bible - { version . abbreviationLocal } ( { version . languageLocal } , { version . descriptionLocal } ) " , icon_url = " attachment://icon.png " )
2024-04-06 06:15:00 -04:00
await ctx . send ( embed = embed , file = icon )
2024-02-01 21:09:53 -05:00
else :
await ctx . send ( f " ## { passage [ ' reference ' ] } \n { passage [ ' content ' ] } " )