PythonでiCal形式のQRコードを自動生成

# はじめの前のおねがい
できれば「いいね♡」をお願いします。励みになります。

# はじめに
このコードは**Python3**に対応したiCal形式のQRコードを自動生成するためのコードです。

# このコードの目的
iCal形式そのものは、それほど複雑ではないので手入力で済ますことができたり、Excelを上手に使って、生成することは可能なのですが、Pythonを使えばカスタマイズの幅がより広がるために作りました。
また、本コードの目玉としてはQRコードをPNG形式でソースコードと同じフォルダ（ディレクトリ）に自動生成する点です。

# 本コードを実行するとどうなるか
本コードを実行すると
1. コードの最初の変数を元にiCal形式テキストを生成
1. QRコードを作成
1. QRコードのPNG画像名を表示「YYYY-MM-DD_［summary変数で指定された文字］」
1. 生成結果を表示
1. 生成されたファイル名を表示

# 注意点
1. 本コードでは変数の書き方に要件が存在します。要件から外れるとエラーが出ますが、エラー回避の処理ルーチンは特に作っていませんのでお気をつけください。
1. テキスト情報が非常に多い結果、生成されるQRコードは非常に複雑なものになるために、ある程度の表示サイズでなければ認識できないなどのエラーが発生します。

## Pythonの必要なモジュール
Pythonに関して必要なモジュールは“json”と“pyperclip”のみです。
```zsh:pip
pip install datetime
pip install qrcode
```

# ソースコード
```python:iCalQRCodeGenerator.py
import datetime
import qrcode

# ユーザーが入力するべきイベント情報
event_date = "2024-06-12"  # YYYY-MM-DD 形式
start_time = "22:00"       # HH:MM 形式
end_time = "23:59"         # HH:MM 形式
summary = "タイトル"        # カレンダータイトル
description = "本文" # カレンダー本文
url = "https://www.google.co.jp" # 参照URL
prod_id = "-//iCalQRCodeGenerator//Python 3//JP" # クリエイター情報

# アラート設定
first_alert_time = "01:00"  # デフォルトは1時間前、HH:MM形式
second_alert_time = "0"  # デフォルトは開始時間（開始時間を指定する場合は「0」と入力）

class ICalendarEvent:
    def __init__(self, event_date, start_time, end_time, summary, description, url, prod_id):
        self.event_date = event_date
        self.start_time = start_time
        self.end_time = end_time
        self.summary = summary
        self.description = description
        self.url = url
        self.prod_id = prod_id
        self.dtstamp = datetime.datetime.now().strftime("%Y%m%dT%H%M%SZ")
        self.uid = self.generate_uid()
        self.start_datetime = self.convert_to_ical_format(event_date, start_time)
        self.end_datetime = self.convert_to_ical_format(event_date, end_time)

    def generate_uid(self):
        current_time = datetime.datetime.now()
        return current_time.strftime("%Y%m%d%H%M%S%f") + "@example.com"

    def convert_to_ical_format(self, date, time):
        return datetime.datetime.strptime(f"{date} {time}", "%Y-%m-%d %H:%M").strftime("%Y%m%dT%H%M%S")

    def convert_alert_time(self, alert_time):
        if alert_time == "0":
            return "-PT0M"
        else:
            hours, minutes = map(int, alert_time.split(":"))
            total_minutes = hours * 60 + minutes
            return f"-PT{total_minutes}M"

    def generate_icalendar_text(self, first_alert_time, second_alert_time):
        first_alert_trigger = self.convert_alert_time(first_alert_time)
        second_alert_trigger = self.convert_alert_time(second_alert_time)

        return f"""BEGIN:VCALENDAR
VERSION:2.0
PRODID:{self.prod_id}
BEGIN:VEVENT
UID:{self.uid}
DTSTAMP:{self.dtstamp}
DTSTART;TZID=Asia/Tokyo:{self.start_datetime}
DTEND;TZID=Asia/Tokyo:{self.end_datetime}
SUMMARY:{self.summary}
DESCRIPTION:{self.description}
URL:{self.url}
BEGIN:VALARM
ACTION:DISPLAY
DESCRIPTION:REMINDER
TRIGGER:{first_alert_trigger}
END:VALARM
BEGIN:VALARM
ACTION:DISPLAY
DESCRIPTION:REMINDER
TRIGGER:{second_alert_trigger}
END:VALARM
END:VEVENT
END:VCALENDAR"""

    def save_qr_code(self, icalendar_text, file_name):
        qr = qrcode.QRCode(
            version=1,
            error_correction=qrcode.constants.ERROR_CORRECT_L,
            box_size=10,
            border=4,
        )
        qr.add_data(icalendar_text)
        qr.make(fit=True)
        img = qr.make_image(fill='black', back_color='white')
        img.save(file_name)
        print()
        print(f"QRコード画像が次のファイル名で保存されました: {file_name}")

def main():
    event = ICalendarEvent(event_date, start_time, end_time, summary, description, url, prod_id)
    icalendar_text = event.generate_icalendar_text(first_alert_time, second_alert_time)

    # ファイル名を生成
    file_name = f"{event_date}_{summary.replace(' ', '_').replace('「', '').replace('」', '')}.png"

    # iCalendarテキストを出力
    print("生成されたiCalendarテキスト:")
    print(icalendar_text)

    # QRコードを保存
    event.save_qr_code(icalendar_text, file_name)

if __name__ == "__main__":
    main()
```
以上です。お役に立てれば幸いです。