BuyeeScraper/bot.py

259 lines
9.7 KiB
Python
Raw Permalink Normal View History

2024-09-15 18:14:13 +08:00
import os
import json
import asyncio
from datetime import datetime, timedelta
import requests
from bs4 import BeautifulSoup
import nextcord
from nextcord.ext import tasks, commands
2024-09-15 18:14:13 +08:00
def load_config(config_name):
if not os.path.exists(config_name):
return None
with open(config_name, "rt", encoding="utf-8") as f:
return json.load(f)
2024-09-15 18:14:13 +08:00
def save_config(config_name, config):
with open(config_name, 'wt', encoding="utf-8") as f:
json.dump(config, f, indent=1, ensure_ascii=False)
2024-09-15 18:14:13 +08:00
# dictionary of urls and time they were added
processed_urls = {}
config = load_config("config.json")
if config is None:
config = {"deepl_key": "", "discord_bot_token": "", "ping_terms": {}}
save_config("config.json", config)
if not config.get("deepl_key") or not config.get("discord_bot_token"):
raise Exception("Config file is missing some values")
intents = nextcord.Intents.default()
bot = commands.Bot(command_prefix=".", intents=intents)
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36'}
2024-09-15 18:14:13 +08:00
deepl_headers = {'Authorization': f'DeepL-Auth-Key {config["deepl_key"]}', 'User-Agent': 'YahooScraper/1.0.0'}
search_term = 'けものフレンズ'
ping_terms: dict = config["ping_terms"]
2024-09-15 18:14:13 +08:00
def add_ping(term, user_id):
if term not in ping_terms:
ping_terms[term] = [user_id]
elif user_id not in ping_terms[term]:
ping_terms[term].append(user_id)
else:
print(f"{user_id} is already being pinged for {term}")
2025-01-30 21:11:00 +08:00
return False
2024-09-15 18:14:13 +08:00
config["ping_terms"] = ping_terms
save_config("config.json", config)
2025-01-30 21:11:00 +08:00
return True
2024-09-15 18:14:13 +08:00
2025-01-30 21:11:00 +08:00
def remove_ping(term, user_id):
if term not in ping_terms:
return False
elif user_id not in ping_terms[term]:
return False
else:
2025-02-05 11:50:18 +08:00
#if there is only one remaining person in the ping term list, delete the whole term
if len(ping_terms[term]) == 1 and ping_terms[term][0] == user_id:
del ping_terms[term]
#if there is more than on person in the ping term list, delete only that user_id
else:
ping_terms[term].remove(user_id)
2025-01-30 21:11:00 +08:00
config["ping_terms"] = ping_terms
save_config("config.json", config)
return True
2025-01-30 21:11:00 +08:00
def get_user_pings(user_id):
return [term for term in ping_terms.keys() if user_id in ping_terms[term]]
2025-01-30 21:11:00 +08:00
async def ping_users(auction_name_jp, auction_name_en):
2024-09-15 18:14:13 +08:00
"""If the name of the listing is particularly interesting, ping some people
- HAV0X"""
users_to_ping = []
interested_terms = []
2024-09-15 18:14:13 +08:00
for term in ping_terms.keys():
if term.lower() in auction_name_jp.lower() or term.lower() in auction_name_en.lower():
interested_terms.append(term)
2024-09-15 18:14:13 +08:00
for user in ping_terms[term]:
if user not in users_to_ping:
users_to_ping.append(user)
2024-09-15 18:14:13 +08:00
if len(users_to_ping) > 0:
ping_message = "Interesting listing, pinging: " + ", ".join([f"<@{user}>" for user in users_to_ping]) + "\nTerms of interest: " + ', '.join([f'"{s}"' for s in interested_terms])
2024-09-15 18:14:13 +08:00
await send_message_text("Japari Modding", "yahoo-auctions", ping_message)
2024-09-15 18:14:13 +08:00
def translate(text: str):
text = requests.post("https://api-free.deepl.com/v2/translate",
json={"text": [text], "target_lang": "EN", 'source_lang': 'JA'}, headers=deepl_headers).json()[
'translations'][0]['text']
return text.replace("Beast Friends", "Kemono Friends")
2024-09-15 18:14:13 +08:00
def embed_auction(service: str, url: str, name: str, name_en: str, thumbnail: str, price=None):
desc = name
if price is not None:
desc += '\nPrice: ' + price
embed = nextcord.Embed(title=name_en, url=url, description=desc)
embed.set_author(name=service)
embed.set_image(url=thumbnail)
return embed
2024-09-15 18:14:13 +08:00
async def send_message(server_name: str, channel_name: str, embed: nextcord.Embed):
for guild in bot.guilds:
if guild.name == server_name:
for channel in guild.channels:
if channel.name == channel_name and isinstance(channel, nextcord.TextChannel):
await channel.send(embed=embed)
break
2024-09-15 18:14:13 +08:00
async def send_message_text(server_name: str, channel_name: str, text: str):
for guild in bot.guilds:
if guild.name == server_name:
for channel in guild.channels:
if channel.name == channel_name and isinstance(channel, nextcord.TextChannel):
await channel.send(content=text)
break
2024-09-15 18:14:13 +08:00
async def check_yahoo_fleamarket(search_term: str, page: int, notify: bool):
url = f'https://buyee.jp/paypayfleamarket/search?keyword={search_term}&order-sort=created_time&page={page}'
response = requests.get(url, headers=headers)
soup = BeautifulSoup(response.text, 'html.parser')
# Find all item listings on the page
item_listings = soup.find('ul', {'class': 'item-lists'}).find_all('li', {'class': 'list'})
date = datetime.now().date()
for item in item_listings:
url = 'https://buyee.jp' + item.find('a').get('href')
if url in processed_urls:
continue
try:
name = item.find('h2', {'class': 'name'}).text
price = item.find('p', {'class': 'price'}).text
thumbnail_data = item.find('img', {'class': "thumbnail"}).get("data-bind")
thumbnail_start = thumbnail_data.find('imagePath: \'') + len('imagePath: \'')
thumbnail_end = thumbnail_data.find('\'', thumbnail_start)
thumbnail = "https:" + thumbnail_data[thumbnail_start:thumbnail_end]
if notify:
name_en = translate(name)
embed = embed_auction("Yahoo! Flea market", url, name, name_en, thumbnail, price)
await send_message("Japari Modding", "yahoo-auctions", embed)
2025-01-30 21:11:00 +08:00
await ping_users(name, name_en)
2024-09-15 18:14:13 +08:00
print('New item added:', url)
processed_urls[url] = date
except Exception as e:
print(url, e)
2024-09-15 18:14:13 +08:00
async def check_yahoo_auction(search_term: str, page: int, notify: bool):
url = f'https://buyee.jp/item/search/query/{search_term}?sort=end&order=d&page={page}'
response = requests.get(url, headers=headers)
soup = BeautifulSoup(response.text, 'html.parser')
# Find all item listings on the page
item_listings = soup.find('ul', {'class': 'auctionSearchResult'}).find_all('li', {'class': 'itemCard'})
date = datetime.now().date()
for item in item_listings:
url = 'https://buyee.jp' + item.find('a').get('href')
if url in processed_urls:
continue
try:
name = item.find('div', {'class': 'itemCard__itemName'}).find('a').text
price = item.find('div', {'class': 'g-price__outer'}).find('span').text
thumbnail = item.find('img', {'class': 'g-thumbnail__image'}).get('data-src').split(';')[0]
if notify:
name_en = translate(name)
embed = embed_auction("Yahoo! JAPAN Auction", url, name, name_en, thumbnail, price)
await send_message("Japari Modding", "yahoo-auctions", embed)
2025-01-30 21:11:00 +08:00
await ping_users(name, name_en)
2024-09-15 18:14:13 +08:00
print('New item added:', url)
processed_urls[url] = date
except Exception as e:
print(url, e)
2024-09-15 18:14:13 +08:00
@bot.event
async def on_ready():
for i in range(1, 4):
await check_yahoo_auction(search_term, i, False)
await check_yahoo_fleamarket(search_term, i, False)
await asyncio.sleep(10)
myLoop.start()
2024-09-15 18:14:13 +08:00
@tasks.loop(minutes=30)
async def myLoop():
fulldate = datetime.now()
print(f'Last check: {fulldate.strftime("%d/%m/%Y %H:%M:%S")}\nCache count: {len(processed_urls)}')
try:
await check_yahoo_auction(search_term, 1, True)
except Exception as e:
print("Yahoo auction check failed:", e)
try:
await check_yahoo_fleamarket(search_term, 1, True)
except Exception as e:
print("Yahoo flea market check failed:", e)
onlydate = fulldate.date()
for key in list(processed_urls.keys()):
if onlydate - processed_urls[key] > timedelta(weeks=3):
del processed_urls[key]
2025-01-30 21:11:00 +08:00
@bot.slash_command(description="Pings you when auction name contains the given term")
async def ping_me(interaction: nextcord.Interaction, term: str):
2025-01-30 21:11:00 +08:00
if add_ping(term, interaction.user.id):
2025-02-05 11:50:18 +08:00
await interaction.response.send_message(f"Success! You will be pinged for `{term}`", ephemeral=False)
2025-01-30 21:11:00 +08:00
else:
pings = get_user_pings(interaction.user.id)
if len(pings) > 0:
2025-02-05 11:50:18 +08:00
await interaction.response.send_message(f"Failed to add `{term}`. You are pinged for `{', '.join(pings)}`",
ephemeral=True)
2025-01-30 21:11:00 +08:00
else:
2025-02-05 11:50:18 +08:00
await interaction.response.send_message(f"Failed to add `{term}`. You are not pinged for anything",
ephemeral=True)
2025-01-30 21:11:00 +08:00
@bot.slash_command(description="No longer pings you when auction name contains the given term")
async def unping_me(interaction: nextcord.Interaction, term: str):
2025-01-30 21:11:00 +08:00
if remove_ping(term, interaction.user.id):
2025-02-05 11:50:18 +08:00
await interaction.response.send_message(f"Success! You will no longer be pinged for `{term}`", ephemeral=False)
2025-01-30 21:11:00 +08:00
else:
pings = get_user_pings(interaction.user.id)
if len(pings) > 0:
2025-02-05 11:50:18 +08:00
await interaction.response.send_message(f"Failed to remove `{term}`. You are pinged for `{', '.join(pings)}`",
ephemeral=True)
2025-01-30 21:11:00 +08:00
else:
2025-02-05 11:50:18 +08:00
await interaction.response.send_message(f"Failed to remove `{term}`. You are not pinged for anything",
ephemeral=True)
2025-01-30 21:11:00 +08:00
2024-09-15 18:14:13 +08:00
bot.run(config["discord_bot_token"], reconnect=True)