Last Sync: 2026-10-28 20:57 (Mobile)

This commit is contained in:
choibk committed 2026-10-28 20:57:10 +09:00
1 parent 07ba98b0c9
commit 5ae4881054
205 files changed
+19078 -10009

No files matched your search

+379
View File
@@ -0,0 +1,379 @@
import json
import calendar
from datetime import datetime
def generate_universal_calendar():
print("=" * 50)
print(" 옵시디언 캔버스 대형 달력 자동 생성 프로그램 ")
print("=" * 50)
# 1. 사용자로부터 연도 및 월 입력 받기
try:
year = int(input("▶ 생성할 연도를 입력하세요 (예: 2026): "))
month = int(input("▶ 생성할 월을 입력하세요 (1~12): "))
if not (1 <= month <= 12):
print("❌ 월은 1부터 12 사이의 숫자여야 합니다.")
return
except ValueError:
print("❌ 올바른 숫자를 입력해주세요.")
return
# 2. 달력의 레이아웃 및 크기 기본 사양 정의
card_width = 320
day_height = 140
box_height = 100
gap_x = 20
gap_y = 20
# 일자 카드 1개 + 하단 10개 박스가 차지하는 1주일 행(Row)의 총 높이
row_total_height = day_height + gap_y + (box_height * 10) + (gap_y * 10) # 1380px
# 3. 해당 월의 요일 정보 및 일수 자동 계산
# weekday_start: 0(월요일) ~ 6(일요일)
# num_days: 해당 월의 총 일수 (28~31)
weekday_start, num_days = calendar.monthrange(year, month)
# 일요일 시작 달력 규격을 위해 인덱스 조정 (기본 파이썬은 월요일 시작)
# 파이썬(월=0, 화=1 ... 토=5, 일=6) -> 변경(일=0, 월=1, 화=2 ... 토=6)
start_offset = (weekday_start + 1) % 7
nodes = []
# 4. 최상단 대형 메인 헤더 타이틀 생성
nodes.append({
"id": "calendar-main-title",
"type": "text",
"text": f"# 📅 {year}년 {month}월 (Calendar)",
"x": 0,
"y": -120,
"width": (card_width * 7) + (gap_x * 6), # 7열 전체 폭에 정렬 (2360px)
"height": 100,
"color": "3" # 노란색 강조
})
# 5. 고정 요일 머리글 배치 (일요일 ~ 토요일 순서)
weekdays = [
{"name": "☀️ 일요일", "color": "1"}, # 일요일 주황/적색 강조
{"name": "월요일", "color": None},
{"name": "화요일", "color": None},
{"name": "수요일", "color": None},
{"name": "목요일", "color": None},
{"name": "금요일", "color": None},
{"name": "🐳 토요일", "color": "2"} # 토요일 청색 강조
]
for idx, day_info in enumerate(weekdays):
w_node = {
"id": f"w-header-{idx}",
"type": "text",
"text": f"### {day_info['name']}",
"x": idx * (card_width + gap_x),
"y": 0,
"width": card_width,
"height": 60
}
if day_info["color"]:
w_node["color"] = day_info["color"]
nodes.append(w_node)
# 6. 일자 배치 및 일자별 하단 10개 텍스트 상자 자동 배치 루프
for day in range(1, num_days + 1):
# 시작 요일(offset)을 반영하여 현재 일자가 위치할 7열 바둑판 좌표 계산
grid_pos = (start_offset + day - 1) % 7
week_row = (start_offset + day - 1) // 7
# 현재 일자의 시작 X, Y 물리 좌표 산출
current_x = grid_pos * (card_width + gap_x)
current_y = 80 + (week_row * row_total_height)
# 주말 컬러 색상 코드 할당
day_color = None
if grid_pos == 0: # 일요일
day_color = "1"
elif grid_pos == 6: # 토요일
day_color = "2"
# 메인 일자 노드 삽입
day_node = {
"id": f"day-node-{day}",
"type": "text",
"text": f"## {day}",
"x": current_x,
"y": current_y,
"width": card_width,
"height": day_height
}
if day_color:
day_node["color"] = day_color
nodes.append(day_node)
# 일자 노드 바로 아래에 10단 텍스트 레이어 수직 배치
box_start_y = current_y + day_height + gap_y
for b_idx in range(1, 11):
box_node = {
"id": f"day-{day}-slot-{b_idx}",
"type": "text",
"text": "",
"x": current_x,
"y": box_start_y + ((b_idx - 1) * (box_height + gap_y)),
"width": card_width,
"height": box_height
}
nodes.append(box_node)
# 7. 옵시디언 캔버스 데이터 최종 통합 규칙 선언
canvas_json_structure = {
"nodes": nodes,
"edges": []
}
# 8. 파일로 내보내기 수행
output_filename = f"{year}년_{month}월_대형달력.canvas"
with open(output_filename, "w", encoding="utf-8") as file:
json.dump(canvas_json_structure, file, ensure_ascii=False, indent=2)
print("-" * 50)
print(f"🎉 작성이 완료되었습니다! 총 {len(nodes)}개의 개체가 구성되었습니다.")
print(f"💾 생성된 파일명: {output_filename}")
print("💡 팁: 해당 파일을 옵시디언 보관소(Vault)에 넣어 즉시 열어보세요.")
print("=" * 50)
if __name__ == "__main__":
generate_universal_calendar()
---
이 파이썬 코드를 초보자도 이해할 수 있게 설명해드릴게요!
---
## 🐍 전체 목적
**Obsidian 캔버스용 월간 달력 파일을 자동으로 만들어주는 프로그램이에요.**
사용자가 연도(2026)와 월(10)을 입력하면, Obsidian에서 바로 열 수 있는 `.canvas` 파일을 생성해요.
---
## 📦 사용하는 도구 (import)
```python
import json # JSON 파일 읽기/쓰기
import calendar # 달력 계산 (해당 월의 시작 요일, 총 일수)
from datetime import datetime # 날짜 관련 (현재는 직접 사용 안 함)
```
---
## 🔢 전체 흐름
```
1. 연도, 월 입력 받기
2. 카드 크기/간격 설정
3. 달력 계산 (시작 요일, 총 일수)
4. 메인 제목 카드 생성
5. 요일 헤더 카드 7개 생성 (일~토)
6. 날짜별 카드 생성 (날짜 카드 1개 + 빈 슬롯 10개)
7. JSON으로 묶기
8. .canvas 파일로 저장
```
---
## 📐 레이아웃 설정
```python
card_width = 320 # 카드 가로 크기 (픽셀)
day_height = 140 # 날짜 카드 세로 크기
box_height = 100 # 빈 슬롯 카드 세로 크기
gap_x = 20 # 카드 사이 가로 간격
gap_y = 20 # 카드 사이 세로 간격
```
캔버스는 좌표계(x, y)로 카드를 배치해요. 픽셀 단위로 위치를 직접 계산해야 해요.
---
## 🗓️ 달력 계산의 핵심
```python
weekday_start, num_days = calendar.monthrange(year, month)
```
예) `calendar.monthrange(2026, 10)` → `(3, 31)`
- `3` = 10월 1일이 목요일 (0=월, 1=화, 2=수, **3=목**, 4=금, 5=토, 6=일)
- `31` = 10월은 31일까지
```python
start_offset = (weekday_start + 1) % 7
```
파이썬은 월요일=0으로 시작하는데, 이 달력은 **일요일=0**으로 시작해요.
그래서 +1 후 %7로 인덱스를 조정해요.
---
## 📍 날짜 위치 계산
각 날짜가 캔버스 어디에 놓일지 계산하는 핵심 공식이에요:
```python
grid_pos = (start_offset + day - 1) % 7 # 0~6열 (일~토)
week_row = (start_offset + day - 1) // 7 # 몇 번째 주(행)인지
current_x = grid_pos * (card_width + gap_x) # 가로 위치
current_y = 80 + (week_row * row_total_height) # 세로 위치
```
예) 2026년 10월 1일 (목요일)
- `start_offset` = 4 (목요일이 일 기준 4번째 열)
- `grid_pos` = (4 + 1 - 1) % 7 = **4** → 5번째 열
- `week_row` = (4 + 1 - 1) // 7 = **0** → 첫 번째 행
---
## 🃏 카드(노드) 구조
Obsidian 캔버스의 카드는 이런 JSON 구조예요:
```json
{
"id": "day-node-1", // 고유 ID (겹치면 안 됨)
"type": "text", // 텍스트 카드
"text": "## 1", // 카드 안에 표시될 내용 (마크다운)
"x": 1400, // 가로 위치
"y": 80, // 세로 위치
"width": 320, // 카드 너비
"height": 140, // 카드 높이
"color": "1" // 색상 (선택사항, 1=빨강, 2=파랑, 3=노랑...)
}
```
---
## 🗂️ 날짜 1개당 생성되는 카드 수
날짜 하나당 총 **11개**의 카드가 생겨요:
```
┌─────────────┐ ← 날짜 카드 (예: "## 1")
├─────────────┤ ← 빈 슬롯 1
├─────────────┤ ← 빈 슬롯 2
│ ... │
└─────────────┘ ← 빈 슬롯 10
```
31일 기준 → 31 × 11 = **341개** + 제목/요일 헤더 = 총 **350개** 카드
---
## 💾 파일 저장
```python
canvas_json_structure = {
"nodes": nodes, # 모든 카드 목록
"edges": [] # 연결선 (이 달력엔 없음)
}
with open(output_filename, "w", encoding="utf-8") as file:
json.dump(canvas_json_structure, file, ensure_ascii=False, indent=2)
```
`.canvas` 파일은 사실 **JSON 파일**이에요. Obsidian이 이 JSON을 읽어서 시각적인 캔버스로 보여주는 거예요.
---
## 🚀 실행 방법
```bash
python 파일명.py
```
실행하면:
```
▶ 생성할 연도를 입력하세요 (예: 2026): 2026
▶ 생성할 월을 입력하세요 (1~12): 10
→ 2026년_10월_대형달력.canvas 파일 생성!
```
이 파일을 Obsidian Vault 폴더에 넣으면 바로 열 수 있어요 😊
---
## `%` 와 `//` 설명
---
### `%` — 나머지 연산자
나눗셈 후 **나머지**만 반환해요.
```python
10 % 3 = 1 # 10 ÷ 3 = 3 나머지 1
7 % 7 = 0 # 7 ÷ 7 = 1 나머지 0
5 % 7 = 5 # 5 ÷ 7 = 0 나머지 5
```
달력 코드에서는 이렇게 써요:
```python
grid_pos = (start_offset + day - 1) % 7
```
`% 7` 을 하면 결과가 항상 **0~6 사이**로 유지돼요.
→ 7이 되면 다시 0으로 돌아가서 **열(日~土)을 반복**하는 데 쓰여요.
```
0→일 1→월 2→화 3→수 4→목 5→금 6→토
7→다시 0(일) 8→1(월) ...
```
---
### `//` — 몫 연산자 (버림 나눗셈)
나눗셈 후 **소수점을 버리고 정수만** 반환해요.
```python
10 // 3 = 3 # 10 ÷ 3 = 3.33... → 3
7 // 7 = 1 # 7 ÷ 7 = 1.0 → 1
5 // 7 = 0 # 5 ÷ 7 = 0.71... → 0
```
달력 코드에서는 이렇게 써요:
```python
week_row = (start_offset + day - 1) // 7
```
`// 7` 을 하면 **몇 번째 주(행)인지** 알 수 있어요.
```
1~7번째 날 → 0 (첫 번째 주)
8~14번째 날 → 1 (두 번째 주)
15~21번째 날 → 2 (세 번째 주)
...
```
---
### 두 개를 함께 보면
```python
grid_pos = (start_offset + day - 1) % 7 # 몇 번째 열? (가로 위치)
week_row = (start_offset + day - 1) // 7 # 몇 번째 행? (세로 위치)
```
예) 10월 10일, `start_offset = 4` 라면:
```
(4 + 10 - 1) = 13
13 % 7 = 6 → 6번째 열 = 토요일
13 // 7 = 1 → 1번째 행 = 2번째 주
```
이 두 연산자로 날짜를 **바둑판 좌표**에 배치하는 거예요! 😊