Skip to content

Instantly share code, notes, and snippets.

@puhitaku
Last active January 15, 2023 07:22
Show Gist options
  • Save puhitaku/e61ad819569ac4da203bea9713b2a698 to your computer and use it in GitHub Desktop.
Save puhitaku/e61ad819569ac4da203bea9713b2a698 to your computer and use it in GitHub Desktop.
SHARP Brain の新機種を見つけたら Discord に投げる bot
import io
import json
import os
import re
import sys
import time
from datetime import datetime
import requests as req
from PIL import Image, ImageDraw, ImageFont
from bs4 import BeautifulSoup
hook = os.environ.get('WEBHOOK_URL')
if hook is None:
print('WEBHOOK_URL is not set; no webhook request will be sent', file=sys.stderr)
# フォントはg_達筆(笑)フォント-教漢版がおすすめ
# https://material.animehack.jp/font_gbrushtappitsu.html
font_fn = os.environ.get('FONT', 'font.ttf')
# 某おじさんの画像
# https://user-images.githubusercontent.com/2425178/149267050-aecd1d1c-1d4a-4d8a-b600-bc0808da70e9.jpg
ojisan_fn = os.environ.get('OJISAN', 'ojisan.jpg')
def main():
while True:
try:
res = req.get('https://jp.sharp/edictionary/')
res.encoding = res.apparent_encoding
except:
res = None
if res is None or res.status_code != 200:
time.sleep(60)
continue
if parse_news(res.text):
return
time.sleep(60)
def parse_news(text):
re_brain = re.compile('[A-Z]+-[A-Z]+[0-9]+') # Matches the model names
html = BeautifulSoup(text, 'html.parser')
dates = [datetime.strptime(d.text.strip(), '%Y年%m月%d日') for d in html.select('#news li .date')]
texts = html.select('#news li .text')
items = list(zip(dates, texts))
detect_since = datetime(2022, 1, 1)
models = []
for i in items:
found = [a.text for a in i[1].select('a') if re_brain.match(a.text)]
if found and i[0] > detect_since:
models.extend(found)
if not models:
print('Found no new models')
return False
print(f'Found new models: {" ".join(models)}')
font = ImageFont.truetype(font_fn, 64)
ojisan = Image.open(ojisan_fn)
draws = []
max_w, max_h = 0, 0
# Draw all models and find the max width and height
for model in models:
bbox = font.getmask(model).getbbox()
width, height = bbox[2] + 8, bbox[3] + 8
if width > max_w:
max_w = width
if height > max_h:
max_h = height
im = Image.new('RGBA', (width, height), (255, 255, 255, 0))
draw = ImageDraw.Draw(im)
draw.text((width // 2, height // 2), model, font=font, fill='black', anchor='mm')
draws.append(im)
agg = Image.new('RGBA', (max_w, (max_h + 8) * len(models)), (0, 0, 0, 0))
# Merge models
for i, d in enumerate(draws):
agg.paste(d, (0, (max_h + 8) * i))
# The boundary of the frame
frame_x1 = 395
frame_x2 = 575
frame_y1 = 50
frame_y2 = 305
frame_width = frame_x2 - frame_x1
frame_height = frame_y2 - frame_y1
# Stretch the model list into the frame and paste
if agg.width > agg.height:
mult = frame_width / agg.width
else:
mult = frame_height / agg.height
agg = agg.resize((int(agg.width * mult), int(agg.height * mult)), Image.LANCZOS)
middle_x = frame_x1 + (frame_width // 2)
middle_y = frame_y1 + (frame_height // 2)
ojisan.paste(agg, (middle_x - agg.width // 2, middle_y - agg.height // 2), agg)
# POST the generated image to the Discord webhook URL
by = io.BytesIO()
ojisan.save(by, format='JPEG')
files = {'ojisan': ('ojisan.jpg', by.getvalue(), 'image/jpeg')}
payload = {
'payload_json': json.dumps(
{'embeds': [{'title': '新機種情報ページをチェック!', 'url': 'https://jp.sharp/edictionary/'}]}
)
}
req.post(hook, files=files, data=payload)
return True
main()
requests
pillow
beautifulsoup4
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment