506 lines
15 KiB
Python
Executable File
506 lines
15 KiB
Python
Executable File
from bs4 import BeautifulSoup
|
|
import discord
|
|
import json
|
|
import os
|
|
import requests
|
|
import datetime
|
|
from datetime import datetime
|
|
|
|
# prints for debug
|
|
import pprint
|
|
|
|
pp = pprint.PrettyPrinter(indent=4)
|
|
|
|
wiki_url = "https://starcitizen.tools/"
|
|
|
|
|
|
async def send_alert(self, channel, embed):
|
|
await self.bot.get_channel(channel).send(embed=embed)
|
|
|
|
|
|
def build_alert_embed(
|
|
color, thumbnail=None, author=None, image=None, details=None, link=None
|
|
):
|
|
embed = discord.Embed(description="-------", color=color, type="rich")
|
|
|
|
if thumbnail:
|
|
embed.set_thumbnail(url=thumbnail)
|
|
|
|
embed.set_author(name=author)
|
|
|
|
if image:
|
|
embed.set_image(url=image)
|
|
|
|
embed.add_field(name="Details", value=details, inline=True)
|
|
|
|
embed.add_field(
|
|
name="LINK",
|
|
value=link,
|
|
inline=False,
|
|
)
|
|
|
|
return embed
|
|
|
|
|
|
def write_incident_file(file_path, url, details):
|
|
info_dict = {
|
|
"incident_link": url,
|
|
"details": details,
|
|
}
|
|
with open(file_path, "w") as out_file:
|
|
out_file.write(json.dumps(info_dict))
|
|
|
|
|
|
async def rsi_find(player):
|
|
player_url = "https://api.starcitizen-api.com/%s/v1/live/user/%s" % (
|
|
os.getenv("star_citizen_token").replace('"', ""),
|
|
player,
|
|
)
|
|
response = requests.get(player_url).json()
|
|
|
|
if not response["data"]:
|
|
embed = discord.Embed(
|
|
description="❌❌❌",
|
|
color=discord.Color.red(),
|
|
type="rich",
|
|
title="Player %s does not exist" % player,
|
|
)
|
|
return embed
|
|
|
|
embed = discord.Embed(
|
|
description="-------",
|
|
color=discord.Color.blue(),
|
|
type="rich",
|
|
title="%s's Star citizen information" % response["data"]["profile"]["handle"],
|
|
)
|
|
|
|
embed.add_field(
|
|
name="Link to profile",
|
|
value=response["data"]["profile"]["page"]["url"],
|
|
inline=False,
|
|
)
|
|
embed.add_field(
|
|
name="Player ID",
|
|
value=response["data"]["profile"]["id"],
|
|
inline=True,
|
|
)
|
|
embed.add_field(
|
|
name="Enlisted",
|
|
value=response["data"]["profile"]["enlisted"].split("T")[0],
|
|
inline=True,
|
|
)
|
|
|
|
embed.set_author(
|
|
name=response["data"]["profile"]["badge"],
|
|
icon_url=response["data"]["profile"]["badge_image"],
|
|
url=response["data"]["profile"]["page"]["url"],
|
|
)
|
|
embed.set_thumbnail(url=response["data"]["profile"]["image"])
|
|
|
|
embed.add_field(name="-------", value="", inline=False)
|
|
if "sid" in response["data"]["organization"]:
|
|
org_url = "https://api.starcitizen-api.com/%s/v1/live/organization/%s" % (
|
|
os.getenv("star_citizen_token").replace('"', ""),
|
|
response["data"]["organization"]["sid"],
|
|
)
|
|
org_response = requests.get(org_url).json()
|
|
|
|
embed.add_field(
|
|
name="Org Info",
|
|
value="[%s](%s)"
|
|
% (org_response["data"]["sid"], org_response["data"]["url"]),
|
|
inline=True,
|
|
)
|
|
|
|
embed.add_field(
|
|
name="Rank",
|
|
value=response["data"]["organization"]["rank"],
|
|
inline=True,
|
|
)
|
|
|
|
embed.add_field(
|
|
name="Number of members",
|
|
value=org_response["data"]["members"],
|
|
inline=False,
|
|
)
|
|
embed.set_image(url=org_response["data"]["logo"])
|
|
else:
|
|
embed.add_field(
|
|
name="Org Info",
|
|
value="Player is not in an org or it is hidden",
|
|
inline=False,
|
|
)
|
|
|
|
return embed
|
|
|
|
|
|
async def get_ship(ship_name):
|
|
try:
|
|
wiki_ship_name = "_".join(elem for elem in ship_name.split())
|
|
|
|
headers = {
|
|
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/112.0"
|
|
}
|
|
response = requests.get(wiki_url + wiki_ship_name, headers=headers).text
|
|
soup = BeautifulSoup(response, "html.parser")
|
|
|
|
embed = discord.Embed(
|
|
description="-------", color=discord.Color.blue(), type="rich"
|
|
)
|
|
|
|
try:
|
|
item_uuid = (
|
|
soup.find("div", {"class": "infobox__label"}, string="UUID")
|
|
.findNext("div", {"class": "infobox__data"})
|
|
.text
|
|
)
|
|
except Exception:
|
|
item_uuid = "N/A"
|
|
embed.set_footer(text="item UUID: %s" % item_uuid)
|
|
|
|
try:
|
|
description = (
|
|
soup.find("section", {"class": "citizen-section-collapsible"})
|
|
.findNext("p")
|
|
.text
|
|
)
|
|
except Exception:
|
|
description = "N/A"
|
|
embed.add_field(name="**Description**", value=description, inline=False)
|
|
|
|
ship_image = (soup.find("a", {"class": "mw-file-description"})).img["src"]
|
|
embed.set_image(url=ship_image)
|
|
|
|
ship_name_on_page = soup.find("span", {"class": "mw-page-title-main"}).text
|
|
try:
|
|
manufacturer = (
|
|
soup.find("div", {"class": "infobox__subtitle infobox__data"})
|
|
.findNext("a")
|
|
.text
|
|
)
|
|
except:
|
|
manufacturer = ""
|
|
|
|
embed.set_thumbnail(
|
|
url="https://media.robertsspaceindustries.com/t0q21kbb3zrpt/source.png"
|
|
)
|
|
|
|
embed.set_author(
|
|
name="%s %s" % (manufacturer, ship_name_on_page),
|
|
url="%s%s" % (wiki_url, wiki_ship_name),
|
|
)
|
|
|
|
try:
|
|
ship_role = (
|
|
soup.find("div", {"class": "infobox__label"}, string="Role")
|
|
.findNext("div")
|
|
.text
|
|
)
|
|
except:
|
|
ship_role = ""
|
|
|
|
embed.add_field(name="**Role**", value=ship_role)
|
|
|
|
try:
|
|
ingame_price = requests.get(
|
|
"https://finder.cstone.space/ShipShops1/%s" % item_uuid
|
|
).text
|
|
price_soup = BeautifulSoup(ingame_price, "html.parser")
|
|
|
|
price_table = price_soup.find("div", class_="pricetab").find_next("table")
|
|
|
|
second_row = price_table.find_all("tr")[1]
|
|
|
|
if "Not sold directly or at all" in second_row.text:
|
|
price = "N/A"
|
|
else:
|
|
ingame_price = (
|
|
second_row.find_all("td")[1].get_text(strip=True).replace(" ", ",")
|
|
)
|
|
|
|
price = "[%s](https://finder.cstone.space/ShipShops1/%s)" % (
|
|
ingame_price,
|
|
item_uuid,
|
|
)
|
|
|
|
if "Not available" in ingame_price:
|
|
price = "N/A"
|
|
except:
|
|
price = "N/A"
|
|
|
|
embed.add_field(
|
|
name="**Ingame Price**",
|
|
value=price,
|
|
inline=True,
|
|
)
|
|
try:
|
|
pledge_price = (
|
|
soup.find("div", {"class": "infobox__label"}, string="Standalone")
|
|
.findNext("span", {"class": "smwtext"})
|
|
.text
|
|
)
|
|
except Exception:
|
|
pledge_price = "N/A"
|
|
|
|
try:
|
|
links = soup.find_all("a", {"class": "external text"})
|
|
pledge_store_link = list(filter(lambda x: "Pledge" in x.text, links))[0][
|
|
"href"
|
|
]
|
|
|
|
embed.add_field(
|
|
name="**Pledge Price**",
|
|
value="[%s](%s#buying-options)" % (pledge_price, pledge_store_link),
|
|
inline=True,
|
|
)
|
|
except Exception:
|
|
embed.add_field(
|
|
name="**Pledge Price**",
|
|
value=pledge_price,
|
|
inline=True,
|
|
)
|
|
try:
|
|
loaner = (
|
|
soup.find("div", {"class": "infobox__label"}, string="Loaner")
|
|
.findNext("div", {"class": "infobox__data"})
|
|
.text
|
|
)
|
|
embed.add_field(
|
|
name="**Loaner(s)**",
|
|
value=loaner,
|
|
inline=True,
|
|
)
|
|
except Exception:
|
|
pass
|
|
|
|
try:
|
|
price_table = price_soup.find("div", class_="pricetab").find_next("table")
|
|
|
|
buy_location = ", ".join(
|
|
[
|
|
x.find("td").get_text(strip=True).split("-")[-1].strip()
|
|
for x in price_table.find_all("tr")
|
|
if x.find("td")
|
|
]
|
|
)
|
|
embed.add_field(
|
|
name="**Buyable At**",
|
|
value=buy_location,
|
|
inline=True,
|
|
)
|
|
except Exception:
|
|
pass
|
|
|
|
embed.add_field(name="-------", value="", inline=False)
|
|
try:
|
|
cargo_capacity = (
|
|
soup.find("div", {"class": "infobox__label"}, string="Cargo")
|
|
.findNext("span", {"class": "smwtext"})
|
|
.text
|
|
)
|
|
except Exception:
|
|
cargo_capacity = "N/A"
|
|
embed.add_field(name="**Cargo Capacity**", value=cargo_capacity, inline=True)
|
|
|
|
try:
|
|
health = (
|
|
soup.find("div", {"class": "infobox__label"}, string="Health")
|
|
.findNext("div", {"class": "infobox__data"})
|
|
.text
|
|
)
|
|
except Exception:
|
|
health = "N/A"
|
|
|
|
embed.add_field(name="**Ship Health**", value=health, inline=True)
|
|
|
|
try:
|
|
quantum_fuel = (
|
|
soup.find("div", {"class": "infobox__label"}, string="Quantum capacity")
|
|
.findNext("span", {"class": "smwtext"})
|
|
.text
|
|
)
|
|
except Exception:
|
|
quantum_fuel = "N/A"
|
|
|
|
embed.add_field(
|
|
name="**Quantum Fuel Capacity**", value=quantum_fuel, inline=True
|
|
)
|
|
|
|
try:
|
|
top_speed = (
|
|
soup.find("div", {"class": "infobox__label"}, string="Max speed")
|
|
.findNext("span", {"class": "smwtext"})
|
|
.text
|
|
)
|
|
except Exception:
|
|
top_speed = "N/A"
|
|
|
|
embed.add_field(name="**Top Speed**", value=top_speed, inline=True)
|
|
|
|
try:
|
|
crew_size = (
|
|
soup.find("div", {"class": "infobox__label"}, string="Crew")
|
|
.findNext("div", {"class": "infobox__data"})
|
|
.text
|
|
)
|
|
except Exception:
|
|
crew_size = "N/A"
|
|
|
|
embed.add_field(name="**Crew Size**", value=crew_size, inline=True)
|
|
|
|
embed.add_field(name="-------", value="", inline=False)
|
|
|
|
try:
|
|
claim_time = (
|
|
soup.find("div", {"class": "infobox__label"}, string="Claim")
|
|
.findNext("div", {"class": "infobox__data"})
|
|
.text
|
|
)
|
|
except Exception:
|
|
claim_time = "N/A"
|
|
|
|
embed.add_field(name="**Insurance claim time**", value=claim_time, inline=True)
|
|
|
|
try:
|
|
expedited_claim_time = (
|
|
soup.find("div", {"class": "infobox__label"}, string="Expedite")
|
|
.findNext("div", {"class": "infobox__data"})
|
|
.text
|
|
)
|
|
except Exception:
|
|
expedited_claim_time = "N/A"
|
|
embed.add_field(
|
|
name="**Expedite claim time**", value=expedited_claim_time, inline=True
|
|
)
|
|
|
|
try:
|
|
expedite_fee = (
|
|
soup.find("div", {"class": "infobox__label"}, string="Expedite fee")
|
|
.findNext("div", {"class": "infobox__data"})
|
|
.text
|
|
)
|
|
except Exception:
|
|
expedite_fee = "N/A"
|
|
|
|
embed.add_field(name="**Expedite Fee**", value=expedite_fee, inline=True)
|
|
|
|
embed.add_field(name="-------", value="", inline=False)
|
|
try:
|
|
length = (
|
|
soup.find("div", {"class": "infobox__label"}, string="Length")
|
|
.findNext("span", {"class": "smwtext"})
|
|
.text
|
|
)
|
|
except Exception:
|
|
length = "N/A"
|
|
|
|
embed.add_field(name="**Length**", value=length, inline=True)
|
|
|
|
try:
|
|
width = (
|
|
soup.find("div", {"class": "infobox__label"}, string="Width")
|
|
.findNext("span", {"class": "smwtext"})
|
|
.text
|
|
)
|
|
except Exception:
|
|
width = "N/A"
|
|
|
|
embed.add_field(name="**Width**", value=width, inline=True)
|
|
|
|
try:
|
|
height = (
|
|
soup.find("div", {"class": "infobox__label"}, string="Height")
|
|
.findNext("span", {"class": "smwtext"})
|
|
.text
|
|
)
|
|
except Exception:
|
|
height = "N/A"
|
|
|
|
embed.add_field(name="**Height**", value=height, inline=True)
|
|
|
|
embed.add_field(
|
|
name="**Link**", value="%s%s" % (wiki_url, wiki_ship_name), inline=False
|
|
)
|
|
|
|
except Exception as e:
|
|
print(e)
|
|
embed = discord.Embed(description="❌", color=discord.Color.red(), type="rich")
|
|
embed.add_field(
|
|
name="**Could not find that ship**",
|
|
value="You gave me %s. Did you spell it right?\n\n(Its also possible my shitty code isnt working)"
|
|
% ship_name,
|
|
inline=True,
|
|
)
|
|
return embed
|
|
|
|
return embed
|
|
|
|
|
|
async def calculate_trade_profies(commodity, scu=None):
|
|
url = "https://portal.uexcorp.space/api/all_prices/pretty_mode/1/"
|
|
|
|
headers = {"api_key": os.getenv("uexcorp_key")}
|
|
|
|
scu_string = "%s scu" % scu
|
|
if not scu:
|
|
scu = 696
|
|
scu_string = "a C2 Hercules full"
|
|
|
|
embed = discord.Embed(
|
|
description="-------", color=discord.Color.blue(), type="rich"
|
|
)
|
|
response = requests.get(url, headers=headers).json()["data"]
|
|
embed.set_author(name=commodity)
|
|
embed.set_thumbnail(
|
|
url="https://media.starcitizen.tools/thumb/b/bb/Shubin_logo_circle.png/120px-Shubin_logo_circle.png"
|
|
)
|
|
|
|
# Loop through every system/outpost and find the cheapest place selling the commodity
|
|
costs = {}
|
|
for systems, stations in response.items():
|
|
for station, trades in stations.items():
|
|
if "buy" in trades and commodity in trades["buy"]:
|
|
costs[station] = trades["buy"][commodity] * int(scu)
|
|
break
|
|
|
|
if len(costs):
|
|
embed.add_field(
|
|
name="**Best place to buy %s of %s**" % (scu_string, commodity),
|
|
value="%s: $%s"
|
|
% (
|
|
min(costs, key=costs.get),
|
|
"{:20,.2f}".format(costs[min(costs, key=costs.get)]).strip(),
|
|
),
|
|
inline=True,
|
|
)
|
|
|
|
# Same logic, but finding the place buying the commodity for the most
|
|
profits = {}
|
|
for systems, stations in response.items():
|
|
for station, trades in stations.items():
|
|
if "sell" in trades and commodity in trades["sell"]:
|
|
profits[station] = trades["sell"][commodity] * int(scu)
|
|
break
|
|
|
|
embed.add_field(
|
|
name="Best palce to sell %s of %s" % (scu_string, commodity),
|
|
value="%s: $%s"
|
|
% (
|
|
max(profits, key=profits.get),
|
|
"{:20,.2f}".format(profits[max(profits, key=profits.get)]).strip(),
|
|
),
|
|
inline=True,
|
|
)
|
|
|
|
if len(costs) and len(profits):
|
|
net_profit = float(profits[max(profits, key=profits.get)]) - float(
|
|
costs[min(costs, key=costs.get)]
|
|
)
|
|
embed.add_field(
|
|
name="**Net Profit**",
|
|
value="$%s" % "{:20,.2f}".format(net_profit).strip(),
|
|
inline=True,
|
|
)
|
|
|
|
return embed
|