File size: 6,586 Bytes
568bbca
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c0206de
 
 
 
 
 
 
 
 
 
 
5733dea
 
 
 
 
 
 
 
723ba3b
5733dea
 
 
 
 
 
 
 
 
 
 
 
 
 
 
723ba3b
 
568bbca
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c0206de
 
 
 
5733dea
 
 
 
 
 
 
 
 
 
 
 
 
c0206de
5733dea
 
 
 
 
 
 
 
 
 
c0206de
5733dea
ce36f11
568bbca
 
 
 
 
 
c0206de
 
568bbca
ecf9952
c0206de
568bbca
723ba3b
5733dea
723ba3b
c0206de
 
723ba3b
c0206de
 
 
568bbca
c0206de
5733dea
c0206de
568bbca
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
#!/usr/bin/env python3
"""
CSVからサークルデータのJSONを生成するスクリプト
"""

import os
import sys
import csv
import json

sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))

from utils.logger import setup_logger
from utils.json import get_file_path_from_config, json_dumps

# --- ロギングの設定 ---
log = setup_logger(__name__)


def parse_bool(value: str) -> bool:
    """文字列をブール値に変換"""
    return value.lower() in ("true", "1", "yes")


def parse_int(value: str) -> int | None:
    """文字列を整数に変換(空の場合はNone)"""
    if not value or value.strip() == "":
        return None
    try:
        return int(value)
    except ValueError:
        return None


def parse_list(value: str, delimiter: str = "|") -> list[str]:
    """区切り文字で分割してリストに変換"""
    if not value or value.strip() == "":
        return []
    return [item.strip() for item in value.split(delimiter) if item.strip()]


def parse_json(value: str) -> list | dict | None:
    """JSON文字列をパースする(空の場合はNone、失敗した場合は空リスト)"""
    if not value or value.strip() == "":
        return None
    try:
        return json.loads(value)
    except json.JSONDecodeError:
        log.warning(f"JSONのパースに失敗しました: {value[:50]}...")
        return []


def convert_annual_schedule(old_schedule: list | None) -> list | None:
    """
    旧形式の年間予定を新形式に変換する。

    旧形式: [{"month": 4, "events": ["新歓", "春季リーグ開幕"]}, ...]
    新形式: [{"period": "4月", "event": "新歓"}, {"period": "4月", "event": "春季リーグ開幕"}, ...]
    """
    if not old_schedule:
        return None

    new_schedule = []
    for item in old_schedule:
        # 旧形式(month + events)の場合
        if "month" in item and "events" in item:
            month = item["month"]
            events = item["events"]
            period = f"{month}月"
            for event in events:
                new_schedule.append({"period": period, "event": event})
        # 新形式(period + event)の場合はそのまま
        elif "period" in item and "event" in item:
            new_schedule.append(item)

    return new_schedule if new_schedule else None


def main():
    """CSVからサークルデータを読み込み circles.json を生成する。"""

    log.info("CSVファイルからサークルデータを読み込みcircles.jsonを生成します。")

    input_csv_path = get_file_path_from_config(
        "circles.original_csv", "resources/original_circles.csv"
    )
    output_json_path = get_file_path_from_config(
        "circles.circles_json", "data/generated/circles.json"
    )

    if not os.path.exists(input_csv_path):
        log.error(f"入力CSVファイルが見つかりません: {input_csv_path}")
        sys.exit(1)

    circles = []
    try:
        with open(input_csv_path, "r", encoding="utf-8") as f:
            reader = csv.DictReader(f)
            for row in reader:
                # 画像データのパース
                images_data = parse_json(row.get("images", ""))
                images = images_data if images_data else []

                # mainImage の決定: images配列の最初の画像(order=0)を使用
                main_image = None
                if images:
                    # order=0 の画像を探す
                    for img in images:
                        if img.get("order", 0) == 0:
                            main_image = img
                            break
                    # order=0 がなければ最初の画像を使用
                    if main_image is None:
                        main_image = images[0]

                # SNSデータのパース(handleフィールドを含む)
                sns_data = parse_json(row.get("sns", ""))
                sns = []
                if sns_data:
                    for sns_item in sns_data:
                        sns.append({
                            "type": sns_item.get("type", ""),
                            "url": sns_item.get("url", ""),
                            "handle": sns_item.get("handle")
                        })

                # 年間予定のパース(新形式に変換)
                annual_schedule_data = parse_json(row.get("annualSchedule", ""))
                annual_schedule = convert_annual_schedule(annual_schedule_data)

                circle = {
                    "circleId": row.get("circleId", ""),
                    "circleName": row.get("circleName", ""),
                    "circleNameKana": row.get("circleNameKana", ""),
                    "projectId": row.get("projectId") or None,
                    "projectName": row.get("projectName") or None,
                    "genre": row.get("genre") or None,
                    "areaCode": row.get("areaCode") or None,
                    "pamphletNumber": parse_int(row.get("pamphletNumber", "")),
                    "shortIntro": row.get("shortIntro") or None,
                    "detailDescription": row.get("detailDescription") or None,
                    "memberCount": parse_int(row.get("memberCount", "")),
                    "memberNote": row.get("memberNote") or None,
                    "activityFrequency": row.get("activityFrequency") or None,
                    "activityFrequencyNote": row.get("activityFrequencyNote") or None,
                    "activityLocation": row.get("activityLocation") or None,
                    "annualFee": parse_int(row.get("annualFee", "")),
                    "otherCosts": row.get("otherCosts") or None,
                    "annualSchedule": annual_schedule,
                    "contactInfo": row.get("contactInfo") or None,
                    "websiteUrl": row.get("websiteUrl") or None,
                    "isArchived": parse_bool(row.get("isArchived", "false")),
                    "images": images,
                    "mainImage": main_image,
                    "sns": sns,
                }
                circles.append(circle)
    except Exception as exc:
        log.error(f"CSVファイルの読み込みに失敗しました: {exc}")
        sys.exit(1)

    os.makedirs(os.path.dirname(output_json_path), exist_ok=True)
    json_dumps(circles, output_json_path)

    log.info(f"サークルデータの生成が完了しました: {output_json_path} ({len(circles)}件)")
    sys.exit(0)


if __name__ == "__main__":
    main()