From 1f3ad5a2bbb0c7971e685d1e9e27bceff943b286 Mon Sep 17 00:00:00 2001 From: ahnbu Date: Fri, 5 Jun 2026 14:20:22 +0900 Subject: [PATCH] fix(util): support app.notion.com copied page URLs Normalize copied Notion app page URLs by extracting the page id from /p/... links. Fixes 4ier/notion-cli#57. Co-Authored-By: Codex --- CHANGELOG.md | 1 + internal/util/url.go | 5 +++-- internal/util/url_test.go | 10 ++++++++++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f8274c9..248ec89 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ | 일시 | 유형 | 범위 | 변경내용 (목적 포함) | |---|---|---|---| +| 2026-06-05 14:19 | fix | util | `app.notion.com/p/...` 복사 URL에서 page ID 추출 지원 — `` 입력 호환성 개선 (#57) | | 2026-04-30 14:20 | feat | page | `page markdown` (GET /v1/pages/:id/markdown) + `page set-markdown` (PATCH, 4가지 모드 replace/append/after/range) 추가 — Notion 서버사이드 마크다운 I/O 일등공민화 (#37) | | 2026-04-30 14:20 | feat | page | `page property` 추가: GET /v1/pages/:id/properties/:id 자동 페이지네이션 — 25개 초과 relation/rollup/rich_text 사일런트 절단 수정 (#38) | | 2026-04-30 14:20 | feat | block | `block update --file ` / `--markdown` 지원 — append/insert와 일관된 마크다운 경험, 블록 타입 불일치 fail-fast (#36) | diff --git a/internal/util/url.go b/internal/util/url.go index e0b4aa3..4e69dee 100644 --- a/internal/util/url.go +++ b/internal/util/url.go @@ -8,7 +8,8 @@ import ( var ( // Match Notion URLs like https://www.notion.so/page-title-abc123def456 // or https://www.notion.so/workspace/abc123def456?v=... - notionURLRe = regexp.MustCompile(`(?:notion\.so|notion\.site)/(?:.*?)([a-f0-9]{32}|[a-f0-9-]{36})`) + // or https://app.notion.com/p/page-title-abc123def456?source=copy_link + notionURLRe = regexp.MustCompile(`(?:notion\.so|notion\.site|app\.notion\.com)/(?:.*?)([a-f0-9]{32}|[a-f0-9-]{36})`) uuidRe = regexp.MustCompile(`^[a-f0-9]{8}-?[a-f0-9]{4}-?[a-f0-9]{4}-?[a-f0-9]{4}-?[a-f0-9]{12}$`) plainIDRe = regexp.MustCompile(`^[a-f0-9]{32}$`) ) @@ -19,7 +20,7 @@ func ResolveID(input string) string { input = strings.TrimSpace(input) // Full URL - if strings.Contains(input, "notion.so") || strings.Contains(input, "notion.site") { + if strings.Contains(input, "notion.so") || strings.Contains(input, "notion.site") || strings.Contains(input, "app.notion.com") { matches := notionURLRe.FindStringSubmatch(input) if len(matches) > 1 { return formatUUID(matches[1]) diff --git a/internal/util/url_test.go b/internal/util/url_test.go index aa41c02..716e546 100644 --- a/internal/util/url_test.go +++ b/internal/util/url_test.go @@ -33,6 +33,16 @@ func TestResolveID(t *testing.T) { input: "https://www.notion.so/My-Page-c9e9f681ec8e4eb7be25bbbe479b05b0?v=abc123", want: "c9e9f681-ec8e-4eb7-be25-bbbe479b05b0", }, + { + name: "app.notion.com /p copied URL with slug", + input: "https://app.notion.com/p/My-Page-c9e9f681ec8e4eb7be25bbbe479b05b0?source=copy_link", + want: "c9e9f681-ec8e-4eb7-be25-bbbe479b05b0", + }, + { + name: "app.notion.com /p copied URL without slug", + input: "https://app.notion.com/p/c9e9f681ec8e4eb7be25bbbe479b05b0", + want: "c9e9f681-ec8e-4eb7-be25-bbbe479b05b0", + }, { name: "short string passthrough", input: "abc123",