※この記事はUdon Advent Calendar 2024 - Adventarの10日目の記事です。
はじめに
こんにちは。Udonです。このAdvent Calendarも10日目となりました。
さて、Adventarなんですが、マイページからGoogle Calendarなどに投稿の予定を読み込むことができるiCalのURLを取得することができます。
このURLを使って、Advent Calendarのリマインドをする方法を紹介します。
iCalのURLの取得
まず、Adventarにログインして、マイページに移動します。
マイページの下の方を見ると、iCalのURLが表示されています。形式は以下のようになっています。
https://adventar.org/calendars/[UserID].ics
これを使っていきます。
作ったもの
自分のサークルのサーバで動かすことにしたので、以下のようにサークルのGitLabにリポジトリを作りました。
pgm_udon / Adventar-Notice · GitLab
Dockerを用いて動作するもので、Pythonベースで記述しました。
使い方
- リポジトリをクローンする
- .env-sample をコピーして .env を作成
- .env に必要な情報を記入
- docker-compose up -d でコンテナを起動
動作の様子
- 午前0時まで待つ
- スケジュールをiCalから取得
- 本日の日付を取得
- 本日が12/26なら終了
- 本日の日付とスケジュールの日付が一致するものを取得
- メールを送信
iCalendar
本当はBeautifulSoupを使って、Adventarのページから情報を取得する方法を考えていたのですが、seleniumを使う必要があり、環境構築が少し大変そうだと思ったので今回はiCalとiCalendarを使ってみました。
def add_schedule():
url=f'{MYPAGE_URL}.ics'
with urllib.request.urlopen(url) as f:
calendar = Calendar.from_ical(f.read())
schedule={}
for component in calendar.walk():
if component.name == "VEVENT":
dtstart = component.get('DTSTART').dt
summary = component.get('SUMMARY')
key=f'{dtstart}'
element=f'{summary}'
if key in schedule:
schedule[key].append(element)
else:
schedule[key]=[element]
return schedule
この部分でiCalからスケジュールを取得しています。urlは.envに記述したMYPAHE_URL
を用いることで生成しています。
urllib.request.urlopen(url)
でiCalを取得し、Calendar.from_ical(f.read())
でiCalを読み込んでいます。読み込んだデータから、VEVENT
の部分を取得しています。ここには日付やイベント名などの情報が格納されているので、日付のDTSTART
とイベント名のSUMMARY
を取得しています。そして、日付をキー、イベント名を要素として辞書に格納しています。イベントは複数存在する場合があるので、リストとして格納することで複数持てるようにしています。
メール送信の仕組み
メール送信にはsmtplibを使っています。
def send_mail(subject, body):
msg = MIMEText(body, "plain", "utf-8")
msg['Subject'] = subject
msg['From'] = MAIL_SENDUSER
msg['To'] = MAIL_RECIEVEUSER
try:
server = smtplib.SMTP_SSL(MAILSERVER_HOST, MAILSERVER_PORT)
server.sendmail(MAIL_SENDUSER, MAIL_RECIEVEUSER, msg.as_string())
server.quit()
except Exception as e:
print(e)
return
server
部分は各々の環境に合わせる感じですが、自分はサークルのサーバが使えるのでその中で自分自身に送るという流れで実装しています。おそらく、Gmailなどを使う場合は、認証が必要になると思います。
subject
とbody
はそれぞれ別の関数で、日付とイベント名をもとに精製したものを渡すことになっています。
def make_subject(today_str):
return f'{today_str}の更新予定'
def make_body(summary):
res="今日は以下のAdvent Calendarの更新日です。\n\n"
for s in summary:
res+=f'{s}\n'
res+="\n早めに更新してください。"
return res
おわりに
これで毎日午前0時にAdvent Calendarのリマインドが届くようになりました。更新を忘れることも避けることができそうです。
ではまた、次の記事でお会いしましょう。