이 목업은 payload 가 없어 프리렌더 재굽기 대상이 아니다 — `index.html` 한 장이 유일본이고 자산이 지워지면 사람이 되돌려 넣어야 한다(CLAUDE.md 의 ★★ 함정). 지금까지 그 한 장을 이 맥에서만 만들고 있었다. 다른 사람이 이어받을 수 있도록 재료를 전부 올린다. `build/index.html` 은 생성물이라 이그노어 그대로다 — `patch_stay.py` 로 다시 나온다. - build_itinerary.py: 테마 21개 일정 생성. 좌표에서 이동시간을 계산하고(도보 4km/h, 1.5km 초과는 차 25km/h + 주차 5분) 입·퇴실·끼니 창을 맞춘다. 규칙 14종 감사가 **빌드 안**에 있어 하나라도 어기면 payload 를 쓰지 않고 멈춘다 — 검사가 빌드 밖에 있던 동안 뼈대를 고칠 때마다 안 보는 규칙이 생겼다(2026-09-11 REVIEW) - build_story.py: 노래 25곡·인물 57명. 사진은 위키백과 문서 pageimages 만 믿는다 (이름 검색은 동명이인을 끌고 온다 — 이수현→걸그룹, 박성현→골퍼) - patch_stay.py: 캐치프레이즈 100개·자작곡 5곡·객실 사진(A동 12/B동 10)을 넣고 payload 를 갈아 끼운 뒤 inject.css/js 를 `</body>` 앞에 주입해 index.html 을 짠다 - inject.js/css: React 가 다시 그려도 살아남아야 하는 다섯 가지(캐치프레이즈 순환· 헤더 미니 플레이어·지도 링크·사진 저작자 표시·카로셀 제어). `#root` 밖에 둔다 - audit-all.mjs / rails-test.mjs: 실제 브라우저로 34종 검사, 레일 13개 자동 넘김 전수 - README.md: 이어받는 사람이 먼저 읽는 문서. 배포·함정·§7 "내가 틀렸던 6가지" - PROMPTS.md / TEXT.md / REVIEW-2026-09-11.md: 문구 생성 프롬프트 · 전체 텍스트 · 검수 보고 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
230 lines
17 KiB
Python
230 lines
17 KiB
Python
"""가요 다방(군산 노래)과 인물 열전을 다시 채운다.
|
||
|
||
★ 지어내지 않는다.
|
||
· 노래: '음악의 오솔길' 의 군산·전북 지역노래 정리에서 온 목록이다(곡명·가수·작사·작곡·연도).
|
||
링크는 **유튜브 검색 주소**다 — 영상 ID 를 박으면 틀린 영상이 붙을 수 있고, 우리가 그걸
|
||
한 곡씩 확인하지 않았다. 검색은 틀릴 수가 없다.
|
||
· 인물: 한국어 위키백과 '군산시 출신' 분류에서 뽑아 문서 첫 문단으로 한 줄을 적었다.
|
||
사진은 넣지 않는다(초상권 · 2026-09-10 결정). 출처 링크는 그 사람의 위키 문서다.
|
||
|
||
★ 50명을 억지로 채우지 않는다 — 분류에 실제로 있는 사람만 담는다.
|
||
노래도 마찬가지다. 확인된 곡이 25곡이면 25곡이다.
|
||
"""
|
||
import json
|
||
import urllib.parse
|
||
from pathlib import Path
|
||
|
||
SP = Path(__file__).parent
|
||
SRC = SP / "stay-payload-new.json"
|
||
|
||
payload = json.loads(SRC.read_text(encoding="utf-8"))
|
||
SECT = {s["id"]: s for s in payload["theme"]["sections"]}
|
||
|
||
SONG_SOURCE = {"name": "음악의 오솔길 — 군산 관련 노래",
|
||
"url": "https://old-music.tistory.com/entry/%EA%B5%B0%EC%82%B0-%EA%B4%80%EB%A0%A8-%EB%85%B8%EB%9E%98"}
|
||
|
||
# (곡명, 가수, 작사, 작곡, 연도, 라벨색, 한 줄)
|
||
# ★ 연도·작사·작곡을 모르면 비운다. "미상" 이라고 적지 않는다 — 렌더러가 없는 칸을 안 그린다.
|
||
SONGS = [
|
||
("잘 있거라 군산항", "안다성", "손석우", "손석우", 1963, "#2f6b4f",
|
||
"월명산 고갯길로 시작하는 이별가. 군산을 노래한 곡 가운데 가장 널리 알려졌습니다."),
|
||
("헤어진 군산항", "박제연", "송운선", "송운선", 1965, "#2a6053",
|
||
"비 내리는 밤 부두에서 헤어지는 노래입니다."),
|
||
("님 떠난 군산항", "이미자", "조형식", "백영호", 1966, "#1d3c74",
|
||
"떠나는 배를 보내는 항구의 정서를 담았습니다."),
|
||
("금강 나그네", "이미자", "이병훈", "박춘석", 1966, "#d4551f",
|
||
"금강 하구와 군산항 부두를 배경으로 한 곡입니다."),
|
||
("잘 있거라 군산항구", "최정자", "최치수", "유금춘", 1967, "#8a4b2a",
|
||
"떠나는 사람의 말로 부르는 이별가입니다."),
|
||
("군산 마도로스", "이상열", None, None, 1967, "#334b6d",
|
||
"항구를 드나들던 뱃사람의 노래입니다."),
|
||
("군산 부르스", "유주용", "반야월", "강도미", 1969, "#4a3f6b",
|
||
"1960년대 말 군산 거리의 분위기를 담은 곡입니다."),
|
||
("이별의 군산항 부두", "최정자", "최치수", "유금춘", 1969, "#6b2f3a",
|
||
"부두에서의 이별을 다시 한 번 부른 곡입니다."),
|
||
("군산항 부르스", "최하우", "최하우", "김성근", 1984, "#2f5b6b",
|
||
"1980년대에 나온 군산항 노래입니다."),
|
||
("나의 사랑 군산이여", "오단비", "이수", "정종택", 1989, "#a34a2a",
|
||
"군산을 향한 애정을 정면으로 부르는 곡입니다."),
|
||
("군산항 엘레지", "오단비", "이수", "정종택", None, "#7a3b52",
|
||
"항구 도시의 비가입니다."),
|
||
("선유도 아가씨", "오단비", "이수", "서승일", None, "#2b6b7a",
|
||
"고군산군도 선유도를 배경으로 한 곡입니다."),
|
||
("군산찬가", "오단비", "이수", "서승일", None, "#c8873a",
|
||
"은파와 새만금이 가사에 나오는 군산 찬가입니다."),
|
||
("오성산", "오단비", "이수", "서승일", None, "#4f6b3a",
|
||
"금강 하구를 내려다보는 오성산을 노래했습니다."),
|
||
("함께하는 군산", "오은주", "김동찬", "김동찬", None, "#b5603a",
|
||
"군산시가 제작한 음반의 첫 곡입니다."),
|
||
("새만금 연가", "채미영", "김동찬", "김동찬 · 김수환", None, "#356b8a",
|
||
"새만금을 소재로 한 곡입니다."),
|
||
("군산시민의 노래", "오단비", "군산문화원", "군산예총", None, "#5a5a4a",
|
||
"금만경 들녘과 서해 바다로 시작하는 시민의 노래입니다."),
|
||
("군산 아줌마", "박솔미", "송두호", "송두호", None, "#a3562a",
|
||
"선창가 거리와 새만금이 함께 나오는 곡입니다."),
|
||
("내 고향 군산항", "정애란", "정애란", "정애란", None, "#6b4a2a",
|
||
"고향으로서의 군산항을 부른 곡입니다."),
|
||
("군산 가는 길", "황상준", None, None, None, "#3a5a4a",
|
||
"군산으로 향하는 길을 제목으로 삼은 곡입니다."),
|
||
("군산 추억", "임인건", None, None, None, "#4a4a6b",
|
||
"재즈 피아니스트 임인건이 군산을 소재로 만든 곡입니다."),
|
||
("군산에서", "임인건", None, None, None, "#3f5f6b",
|
||
"같은 연주자가 군산에서 받은 인상을 담았습니다."),
|
||
("헤어진 군산항", "김창환", "송운선", "송운선", None, "#2a6053",
|
||
"군산시 제작 음반에 다시 실린 판입니다."),
|
||
("금강 아가씨", "이미자", None, None, None, "#d4551f",
|
||
"금강을 배경으로 한 이미자의 또 다른 곡입니다."),
|
||
("금강의 비가", "전승애", None, None, None, "#7a4a6b",
|
||
"금강을 제목에 올린 곡입니다."),
|
||
]
|
||
|
||
|
||
def youtube(title: str, artist: str | None) -> str:
|
||
query = f"{title} {artist or ''}".strip()
|
||
return "https://www.youtube.com/results?search_query=" + urllib.parse.quote(query)
|
||
|
||
|
||
songs = []
|
||
for title, artist, lyricist, composer, year, color, story in SONGS:
|
||
item = {"title": title, "artist": artist, "labelColor": color, "story": story,
|
||
"verified": "확인" if year else "확인필요",
|
||
"listenUrl": youtube(title, artist), "source": SONG_SOURCE}
|
||
if lyricist:
|
||
item["lyricist"] = lyricist
|
||
if composer:
|
||
item["composer"] = composer
|
||
if year:
|
||
item["year"] = year
|
||
songs.append(item)
|
||
|
||
SECT["songs"]["data"] = json.dumps(
|
||
{"kind": "songs", "version": 1, "title": "가요 다방",
|
||
"subtitle": f"군산을 노래한 {len(songs)}곡 — 눌러서 들어 보세요", "items": songs},
|
||
ensure_ascii=False)
|
||
|
||
|
||
# ── 인물 열전 ────────────────────────────────────────────────────────────────
|
||
# (위키 문서 제목, 표시 이름, 연도, 하는 일, 한 줄)
|
||
# ★ 한 줄은 위키 첫 문단을 줄인 것이다. 군산과의 관계가 문서에 적힌 사람만 담는다.
|
||
PEOPLE = [
|
||
("채만식", "채만식", "1902–1950", "소설가", "군산을 무대로 한 『탁류』를 썼습니다. 시내에 문학관이 있습니다."),
|
||
("고은", "고은", "1933–", "시인", "군산에서 태어나 60년 넘게 시를 써 온 시인입니다."),
|
||
("이병훈 (시인)", "이병훈", "1925–2009", "시인", "옥구(지금의 군산) 출신으로 1950년대에 등단한 현대 시인입니다."),
|
||
("심호택", "심호택", "1947–2010", "시인", "민중의 삶을 시로 옮긴 시인입니다."),
|
||
("문효치", "문효치", "1943–", "시인", "군산에서 태어나 1966년 신춘문예로 등단했습니다."),
|
||
("이연주 (시인)", "이연주", "1953–1992", "시인", "짧게 활동하고 떠난 시인입니다."),
|
||
("주하림", "주하림", None, "시인", "군산에서 태어나 2009년 창비신인시인상으로 등단했습니다."),
|
||
("고형곤", "고형곤", "1906–2004", "철학자", "선(禪) 연구로 알려진 철학자이자 정치가입니다."),
|
||
("김선기 (언어철학자)", "김선기", "1907–1992", "언어학자", "호는 무돌. 한글 연구에 힘쓴 언어학자이자 교육자입니다."),
|
||
("반석평", "반석평", "1472–1540", "조선 문신", "노비 출신으로 문과에 급제해 판서에 오른 조선 중종 때 문신입니다."),
|
||
|
||
("김수미", "김수미", "1949–2024", "배우", "「전원일기」 일용 엄니로 오래 기억되는 배우입니다."),
|
||
("송새벽", "송새벽", "1979–", "배우", "군산 출신 배우입니다."),
|
||
("장신영", "장신영", "1984–", "배우", "군산 출신 배우입니다."),
|
||
("이서원", "이서원", "1997–", "배우", "군산 출신 배우입니다."),
|
||
("장재호 (배우)", "장재호", "1986–", "배우", "군산 출신 배우입니다."),
|
||
("강민지 (배우)", "강민지", "1996–", "배우 · 모델", "모델로 시작해 드라마와 영화로 활동 범위를 넓혔습니다."),
|
||
("병헌", "병헌", "1993–", "배우", "그룹 틴탑 활동을 거쳐 배우로 옮겼습니다."),
|
||
("정혁 (모델)", "정혁", "1991–", "모델", "2015년 서울패션위크로 데뷔한 모델 겸 방송인입니다."),
|
||
("김혜선 (희극인)", "김혜선", "1983–", "희극인", "군산 출신 희극 배우입니다."),
|
||
("이옥주 (희극인)", "이옥주", "1969–", "희극인", "군산중앙여고를 나와 1988년 MBC 개그콘테스트 대상을 받았습니다."),
|
||
("박화요비", "박화요비", "1982–", "가수", "R&B 를 주로 부르는 가수입니다."),
|
||
("박윤경 (가수)", "박윤경", "1970–", "가수", "군산 출신 가수 겸 기업인입니다."),
|
||
("하준 (가수)", "하준", "1965–", "가수", "군산 출신 가수입니다."),
|
||
|
||
("고건", "고건", "1938–", "정치인", "제30·35대 국무총리를 지냈습니다. 아버지는 철학자 고형곤입니다."),
|
||
("강봉균 (정치인)", "강봉균", "1943–2017", "정치인", "재정경제부 장관과 3선 국회의원을 지냈습니다."),
|
||
("양일동", "양일동", "1912–1980", "정치인", "옥구군 서수면 출신으로 야당 정치인으로 활동했습니다."),
|
||
("김관영", "김관영", "1969–", "정치인", "전북특별자치도지사입니다. 회계사·변호사를 거쳤습니다."),
|
||
("채영석", "채영석", "1934–2006", "정치인", "군산에서 3선 국회의원을 지냈습니다."),
|
||
("신영대", "신영대", "1968–", "정치인", "군산 지역구 국회의원입니다."),
|
||
("김의겸", "김의겸", "1963–", "언론인 · 정치인", "한겨레 기자를 거쳐 청와대 대변인과 국회의원을 지냈습니다."),
|
||
("함운경", "함운경", "1964–", "정치인", "1980년대 학생운동가 출신입니다."),
|
||
("임병찬", "임병찬", "1851–1916", "의병장", "최익현과 함께 거병한 구한말 의병장으로, 단식 끝에 순국했습니다."),
|
||
("이수현 (1895년)", "이수현", "1895–1980", "독립운동가", "호는 산남. 군산 출신 독립운동가입니다."),
|
||
("전진 (1923년)", "전진", "1923–2012", "비전향 장기수", "군산 출신으로 오래 수감 생활을 했습니다."),
|
||
|
||
("이길여", "이길여", "1932–", "의료인 · 교육자", "가천대학교 길병원을 세우고 가천대 총장을 맡고 있습니다."),
|
||
("최길선", "최길선", "1946–", "기업인", "현대중공업 회장을 지낸 조선업 경영인입니다."),
|
||
("은성수 (공무원)", "은성수", "1961–", "공무원", "제7대 금융위원회 위원장을 지냈습니다."),
|
||
("채금석", "채금석", "1904–1995", "축구 선수", "일제강점기 경성 축구단 선수로 경평축구대항전에 나섰습니다."),
|
||
|
||
("박경완", "박경완", "1972–", "야구 선수", "SK 와이번스 포수로 한국 야구의 대표적인 포수였습니다."),
|
||
("조계현", "조계현", "1964–", "야구 선수", "해태 타이거즈 투수로 뛰었습니다."),
|
||
("정명원", "정명원", "1966–", "야구 선수", "현대 유니콘스 투수로 뛰었습니다."),
|
||
("조규제", "조규제", "1967–", "야구 선수", "왼손 투수로 뛰고 지금은 투수코치입니다."),
|
||
("차우찬", "차우찬", "1987–", "야구 선수", "투수로 뛰었고 지금은 야구 해설위원입니다."),
|
||
("이진영 (1980년)", "이진영", "1980–", "야구 선수", "외야수로 뛰었고 지금은 코치입니다."),
|
||
("오지환", "오지환", "1990–", "야구 선수", "LG 트윈스 내야수입니다."),
|
||
("이천웅", "이천웅", "1988–", "야구 선수", "LG 트윈스 외야수로 뛰었습니다."),
|
||
("노상래", "노상래", "1970–", "축구 선수", "공격수로 뛰었고 지도자로 일하고 있습니다."),
|
||
("노수진", "노수진", "1962–", "축구 선수", "공격수로 뛰었고 지금은 체육 교사입니다."),
|
||
("유동우", "유동우", "1968–", "축구 선수", "수비수로 뛰었고 대학 축구부 감독을 맡고 있습니다."),
|
||
("이정효", "이정효", "1975–", "축구 감독", "풀백으로 뛰었고 지금은 프로팀 감독입니다."),
|
||
("박성현 (양궁 선수)", "박성현", "1983–", "양궁 선수", "군산 소룡초에서 활을 처음 잡아 올림픽 금메달을 땄습니다."),
|
||
("김광선 (권투 선수)", "김광선", "1964–", "권투 선수", "1988년 서울 올림픽 복싱 플라이급 금메달리스트입니다."),
|
||
("정경미 (유도 선수)", "정경미", "1985–", "유도 선수", "군산 출신 유도 선수입니다."),
|
||
("전미라", "전미라", "1978–", "테니스 선수", "테니스 선수로 뛰었고 지금은 해설위원입니다."),
|
||
("최서우", "최서우", "1982–", "스키점프 선수", "1998년부터 국가대표로 뛴 스키점프 선수입니다."),
|
||
("한왕용", "한왕용", "1966–", "산악인", "히말라야 8000m 14좌를 세계 11번째로 완등했습니다."),
|
||
("문호준", "문호준", "1997–", "프로게이머", "카트라이더 리그 최다 우승자입니다."),
|
||
]
|
||
|
||
# ★ 사진은 **자유 라이선스인 것만** 싣는다.
|
||
# 위키백과 문서에 사진이 있는 사람은 57명 중 18명이고, 그중 라이선스가 확인되는 17장만 받았다
|
||
# (CC BY / CC BY-SA / KOGL / 공용). 라이선스가 안 읽히는 한 장은 뺐다 — 초상권과 저작권이
|
||
# 미결인 이미지는 싣지 않는다는 이 레포의 규약(DECISIONS 1-2)과 같은 자리다.
|
||
# CC BY-SA 는 저작자 표시가 조건이라 imageCredit 으로 화면에 남긴다(렌더러가 출처 줄에 붙인다).
|
||
PHOTOS = {p["name"]: p for p in json.loads((SP / "people-photos.json").read_text(encoding="utf-8"))}
|
||
|
||
# ★ 위키에 사진이 없는 사람은 **원본 payload 의 사진을 그대로 쓴다**
|
||
# (2026-09-11 사장님: "원래 나오던 것도 안 나옴"). 인물 목록을 새로 만들면서
|
||
# 원본에 있던 8장을 같이 날렸다 — 채만식처럼 위키에 사진이 없는 사람이 빈칸이 됐다.
|
||
# 이 사진들은 원래 이 사이트가 쓰던 것이라 자리로 되돌리는 것이지 새로 가져오는 게 아니다.
|
||
_ORIGINAL = json.loads((SP / "stay-payload.json").read_text(encoding="utf-8"))
|
||
ORIGINAL_PHOTOS = {}
|
||
for _sec in _ORIGINAL["theme"]["sections"]:
|
||
if _sec["id"] != "people":
|
||
continue
|
||
for _item in json.loads(_sec["data"])["items"]:
|
||
if _item.get("imageUrl"):
|
||
ORIGINAL_PHOTOS[_item["name"]] = _item["imageUrl"]
|
||
|
||
# ★ 이름만으로 커먼즈를 검색해 사진을 붙이지 않는다 (2026-09-11 실측).
|
||
# 동명이인이 잡힌다 — 이수현(독립운동가)에 걸그룹 멤버, 은성수(금융위원장)에 축구선수,
|
||
# 박성현(양궁)에 골퍼, 이길여에 건물 사진이 왔다. **틀린 사진은 없는 것만 못하다.**
|
||
# 그 사람의 위키 문서가 대표 사진으로 쓰는 것(pageimages)만 신뢰한다.
|
||
|
||
people = []
|
||
for title, name, years, role, one_line in PEOPLE:
|
||
item = {"name": name, "role": role, "oneLine": one_line, "verified": "확인",
|
||
"source": {"name": "한국어 위키백과",
|
||
"url": "https://ko.wikipedia.org/wiki/" + urllib.parse.quote(title.replace(" ", "_"))}}
|
||
if years:
|
||
item["years"] = years
|
||
photo = PHOTOS.get(name)
|
||
if photo:
|
||
item["imageUrl"] = photo["url"]
|
||
# ★ 렌더러의 imageCredit 은 **문자열**이다(common.tsx:206). 객체를 넣으면 조용히 안 나온다 —
|
||
# CC BY-SA 는 저작자 표시가 조건이라 안 나오면 라이선스를 어기는 것이다.
|
||
item["imageCredit"] = f"사진 {photo['author']} · {photo['license']}"
|
||
elif name in ORIGINAL_PHOTOS:
|
||
item["imageUrl"] = ORIGINAL_PHOTOS[name]
|
||
people.append(item)
|
||
|
||
# ★ 사진 있는 사람을 앞으로 당긴다 (2026-09-11 사장님 지시).
|
||
# 목록은 가로 레일이라 손님이 보는 것은 앞쪽 몇 장이다. 분야별로만 묶어 두면
|
||
# 사진이 흩어져(1·2번 있고 3~8번 없고 9번에 또 있는 식) 레일 앞머리가 글자만 남는다.
|
||
# **분야 순서는 그대로 두고** 사진 유무로만 두 덩이로 가른다 — 안정 정렬이라
|
||
# 같은 덩이 안에서는 문인 → 배우·가수 → 정치 → 기업 → 체육 순서가 유지된다.
|
||
people.sort(key=lambda item: 0 if item.get("imageUrl") else 1)
|
||
|
||
SECT["people"]["data"] = json.dumps(
|
||
{"kind": "people", "version": 1, "title": "인물 열전",
|
||
"subtitle": f"군산이 낳은 사람 {len(people)}명", "items": people},
|
||
ensure_ascii=False)
|
||
|
||
SRC.write_text(json.dumps(payload, ensure_ascii=False), encoding="utf-8")
|
||
print(f"가요 다방 {len(songs)}곡 · 인물 열전 {len(people)}명 (사진 {sum(1 for p in people if p.get(chr(34)+chr(34)) or p.get('imageUrl'))}장)")
|
||
print(" 자작곡 섞임:", any("머뭄" in s["title"] for s in songs))
|