Skip to content

feat(server): 곡 상세에 외부 링크·Last.fm 좋아요·커버 이미지 - #34

Merged
countnine merged 1 commit into
masterfrom
feat/server/song-links-and-lastfm
Aug 17, 2026
Merged

feat(server): 곡 상세에 외부 링크·Last.fm 좋아요·커버 이미지#34
countnine merged 1 commit into
masterfrom
feat/server/song-links-and-lastfm

Conversation

@countnine

Copy link
Copy Markdown
Owner

관리자 화면 곡 상세를 보강한다. /v1 계약과 Windows·Android 앱은 건드리지 않으므로 앱 릴리스가 필요 없다.

조사로 확정한 것

Tunefind API는 개인이 쓸 수 없다. 셀프서비스 가입 창구가 없고 info@tunefind.com으로 라이선스 계약을 맺어야 하며 무료 티어가 없다. robots.txt는 ClaudeBot·anthropic-ai·GPTBot을 전면 차단해 크롤링도 답이 아니다. → 검색 링크만 단다. 주소는 반드시 /search?q=다 — 검색 결과에 흔히 나오는 /search/site?q=는 실측 404다.

Last.fm 좋아요는 공식 API로 읽기·쓰기 모두 된다. track.getInfousername을 주면 userloved가 실려 오고(지금 키로 충분), 켜고 끄기는 POST + api_sig + 세션 키가 필요하다.

Last.fm 이미지는 쓸 수 없다. API 약관이 audio·audiovisual·artwork를 계약 대상에서 명시적으로 제외한다("expressly excluded from this Agreement"). 커버는 iTunes Search에서 따로 가져온다.

바뀐 것

  • 외부 링크 다섯 개 — Last.fm · Tunefind · YouTube · Musixmatch · Genius를 의미 카드가 아니라 머리말 아래로 옮겼다. Tunefind·YouTube는 의미의 출처가 아니라 곡을 더 보러 가는 통로이고, 의미가 비었을 때 카드가 안내하는 "위 링크"가 실제로 위에 있어야 말이 맞는다.
  • Last.fm 좋아요 표시·토글 — 브라우저 승인 플로우(?cb=로 콜백을 그때그때 넘겨 API 계정에 등록할 필요가 없다). 함정: 관리자 쿠키가 SameSite=Strict라 last.fm에서 돌아오는 이동에 실리지 않는다 — 그대로 두면 콜백이 로그인 화면으로 떨어지고 1회용 토큰이 날아간다. 콜백의 신원 증명은 SameSite=Lax인 state 논스 쿠키로 따로 한다. 조회 실패는 "좋아요 안 함"으로 그리지 않는다(꺼진 하트를 보고 누르면 이미 켜 둔 것을 끄게 된다).
  • 커버 이미지 — iTunes Search(키 불필요, 100x100bb.jpg600x600bb.jpg) → Deezer 폴백. 첫 결과를 믿지 않고 MeaningMatch.IsSameSong을 통과시킨다(Genius·Musixmatch에서 이미 겪은 함정). 못 찾은 것도 기억해 열 때마다 다시 부르지 않는다([커버 다시 찾기]로 해제). CSP default-src 'none' 때문에 img-src를 그 두 호스트로 열었다 — 안 열면 이미지가 조용히 안 뜬다.
  • 로그아웃을 우상단으로 — 네비 가운데(대시보드·가사 검색·로그아웃)에 있어 잘못 눌렀다.

저장·롤백

song_links + app_settings(user_version=7). 테이블 추가뿐이라 구 버전 바이너리로 롤백해도 안전하다.

세션 키는 DB에 저장되므로 백업에 Last.fm 쓰기 자격증명이 함께 들어간다 — [연결 해제] 버튼과 last.fm 설정에서의 권한 회수를 문서에 함께 적었다.

새 환경변수

MUSEBASE_LASTFM_SECRET — 없으면 연결 카드와 좋아요 토글이 통째로 사라지고 나머지는 그대로다.

검증

  • 빌드 경고 0, 테스트 333개 통과(38건 추가).
  • 로컬 실서버 스모크: 곡 상세 200 · CSP에 img-src 반영 · 링크 다섯 개 · 커버를 iTunes에서 실제로 찾아 600x600으로 렌더(is1-ssl.mzstatic.com) · secret 없을 때 Last.fm 카드 숨김 · /admin/lastfm/connect가 state 쿠키(samesite=lax; path=/admin/lastfm)를 굽고 303 · state 없는 콜백은 안내로 되돌림.

🤖 Generated with Claude Code

관리자 화면 전용이다. /v1 계약과 앱은 건드리지 않으므로 앱 릴리스가 필요 없다.

- 외부 링크 다섯 개(Last.fm·Tunefind·YouTube·Musixmatch·Genius)를 의미 카드가
  아니라 머리말 아래로. Tunefind·YouTube는 의미의 출처가 아니라 곡을 더 보러
  가는 통로이고, 의미가 비었을 때 카드가 안내하는 "위 링크"가 실제로 위에 있어야
  말이 맞는다.
- Tunefind API는 쓸 수 없다 — 셀프서비스 가입 창구가 없고 라이선스 계약이
  필요하며 무료 티어가 없다. robots.txt는 AI 크롤러를 전면 차단한다. 그래서
  검색 링크만 단다. 주소는 /search?q= — /search/site?q=는 실측 404다.
- Last.fm 좋아요 표시·토글. 읽기는 지금 키로 되고(track.getInfo + username →
  userloved), 쓰기는 브라우저 승인 플로우로 세션 키를 받는다. 관리자 쿠키가
  SameSite=Strict라 last.fm에서 돌아오는 이동에 실리지 않으므로, 콜백의 신원
  증명은 SameSite=Lax인 state 논스 쿠키로 따로 한다. 조회 실패를 "좋아요 안 함"
  으로 그리지 않는다 — 이미 켜 둔 것을 끄게 된다.
- 커버 이미지. iTunes Search(키 불필요) → Deezer 폴백, 첫 결과를 믿지 않고
  MeaningMatch를 통과시킨다. 못 찾은 것도 기억해 열 때마다 다시 부르지 않는다.
  Last.fm 이미지는 쓰지 않는다 — API 약관이 artwork를 계약 대상에서 명시적으로
  제외한다. CSP img-src를 두 호스트로 연다(안 열면 조용히 안 뜬다).
- 로그아웃을 네비 우상단으로. 가운데 있어 잘못 눌렀다.

저장은 song_links + app_settings(user_version=7) — 추가뿐이라 롤백해도 안전하다.
테스트 38건 추가(333개 통과), 경고 0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@countnine
countnine merged commit dd7f0f2 into master Aug 17, 2026
1 check passed
@countnine
countnine deleted the feat/server/song-links-and-lastfm branch August 17, 2026 14:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant