Skip to content

Commit c3c2764

Browse files
committed
Merge develop: 교체 이미지 재다운로드 반영 [skip-notion]
2 parents bbfb957 + 7da2c38 commit c3c2764

2 files changed

Lines changed: 63 additions & 8 deletions

File tree

scripts/notion_to_md.py

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -379,14 +379,19 @@ def download_image(url: str, slug: str, index: int) -> str:
379379
ext = ".jpg"
380380
filename = f"img-{index:02d}{ext}"
381381
filepath = f"{save_dir}/{filename}"
382-
if not os.path.exists(filepath):
383-
r = requests.get(url, timeout=30)
384-
r.raise_for_status()
385-
with open(filepath, "wb") as f:
386-
f.write(r.content)
387-
log(f"이미지 저장: {filepath}")
388-
else:
389-
log(f"이미지 캐시: {filepath}")
382+
# Notion 이미지 URL은 매번 바뀌므로(서명 URL) 파일명 존재만으로 캐시하면
383+
# 교체된 이미지가 반영되지 않는다. 항상 내려받아 내용이 다를 때만 덮어쓴다.
384+
r = requests.get(url, timeout=30)
385+
r.raise_for_status()
386+
new_content = r.content
387+
if os.path.exists(filepath):
388+
with open(filepath, "rb") as f:
389+
if f.read() == new_content:
390+
log(f"이미지 변경 없음: {filepath}")
391+
return f"/img/{_last_seg}/{slug}/{filename}"
392+
with open(filepath, "wb") as f:
393+
f.write(new_content)
394+
log(f"이미지 저장: {filepath}")
390395
return f"/img/{_last_seg}/{slug}/{filename}"
391396

392397

scripts/tests/test_notion_to_md.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import hashlib
66
import json
77
import os
8+
import shutil
89
import sys
910
import tempfile
1011
from pathlib import Path
@@ -634,6 +635,55 @@ def test_multiple_shift_enters(self):
634635
assert "A \nB \nC" in out
635636

636637

638+
# ── 이미지 재다운로드: Notion 이미지 교체 시 같은 index 파일 덮어쓰기 ──────────
639+
640+
class TestDownloadImageRedownload:
641+
"""Notion에서 이미지를 교체하면 URL은 바뀌지만 img-NN 파일명은 동일하다.
642+
파일이 존재해도 새 내용이면 덮어써야 stale 이미지가 남지 않는다."""
643+
644+
def setup_method(self):
645+
self.tmpdir = tempfile.mkdtemp()
646+
self._orig = n.STATIC_IMG_DIR
647+
n.STATIC_IMG_DIR = self.tmpdir
648+
649+
def teardown_method(self):
650+
n.STATIC_IMG_DIR = self._orig
651+
shutil.rmtree(self.tmpdir, ignore_errors=True)
652+
653+
def _mock_response(self, content):
654+
m = MagicMock()
655+
m.content = content
656+
m.raise_for_status = lambda: None
657+
return m
658+
659+
def _prewrite(self, content):
660+
save_dir = os.path.join(self.tmpdir, "blog", "x")
661+
os.makedirs(save_dir, exist_ok=True)
662+
path = os.path.join(save_dir, "img-00.png")
663+
with open(path, "wb") as f:
664+
f.write(content)
665+
return path
666+
667+
@patch.object(n, "requests")
668+
def test_overwrites_when_content_changed(self, mock_requests):
669+
path = self._prewrite(b"OLD-IMAGE")
670+
mock_requests.get.return_value = self._mock_response(b"NEW-IMAGE")
671+
n.download_image("https://notion/new.png", "blog/x", 0)
672+
with open(path, "rb") as f:
673+
assert f.read() == b"NEW-IMAGE"
674+
675+
@patch.object(n, "requests")
676+
def test_no_rewrite_when_identical(self, mock_requests):
677+
# 내용 동일 시 재기록하지 않아 git churn 방지 (mtime 유지)
678+
path = self._prewrite(b"SAME-IMAGE")
679+
os.utime(path, (1_000_000, 1_000_000))
680+
mock_requests.get.return_value = self._mock_response(b"SAME-IMAGE")
681+
n.download_image("https://notion/x.png", "blog/x", 0)
682+
assert os.path.getmtime(path) == 1_000_000
683+
with open(path, "rb") as f:
684+
assert f.read() == b"SAME-IMAGE"
685+
686+
637687
# ── 리스트 항목의 이미지 자식은 최상위(전체 폭)로 hoist ──────────────────────
638688

639689
class TestListItemImageHoisting:

0 commit comments

Comments
 (0)