음악 플랫폼에서 UPC 및 ISRC 코드를 추출하는 텔레그램 봇 만들기
이 텔레그램 봇은 10대 주요 음악 플랫폼에서 앨범, 싱글 등 음악 발매물의 UPC와 ISRC 코드를 자동으로 추출합니다. 스포티파이, 애플뮤직, 얀덱스뮤직, 유튜브뮤직, 디저, 타이달, 사운드클라우드, VK뮤직, 즈부크, 아마존뮤직을 지원합니다. 분배사나 플랫폼 인터페이스를 통해 UPC 코드에 직접 접근할 수 없었던 문제에서 출발했으며, 링크, 발매 ID, 텍스트 쿼리 입력만으로도 정확한 코드를 1~2초 내에 반환합니다. 지능형 캐싱 기술 덕분입니다.
UPC는 앨범이나 싱글과 같은 발매물을 식별하고, ISRC는 각 트랙을 고유하게 식별합니다. 이 두 가지 식별자는 분배사 전환, 저작권 등록, 로열티 추적에 필수적입니다.
시스템 아키텍처
시스템은 모듈식 설계로 구성되어 있습니다:
- URL 파서: 정규 표현식을 사용해 플랫폼을 자동 감지합니다.
- 플랫폼 리졸버: 공식 또는 역설계된 API를 통해 메타데이터를 가져옵니다.
- UPC/ISRC 매칭기: 여러 소스의 데이터를 교차 검증합니다.
- 저장소: 캐시에는 Redis(유효기간 24시간), 분석용으로 PostgreSQL을 사용합니다.
이 구조는 확장 가능한 처리를 가능하게 하며 외부 API 부하를 줄입니다.
import re
from dataclasses import dataclass
from enum import Enum
class Platform(Enum):
SPOTIFY = "spotify"
APPLE_MUSIC = "apple_music"
YANDEX_MUSIC = "yandex_music"
YOUTUBE_MUSIC = "youtube_music"
DEEZER = "deezer"
TIDAL = "tidal"
SOUNDCLOUD = "soundcloud"
VK_MUSIC = "vk_music"
ZVUK = "zvuk"
AMAZON_MUSIC = "amazon_music"
@dataclass
class ParsedLink:
platform: Platform
content_type: str # "album", "track", "artist"
content_id: str
PATTERNS = [
# 스포티파이
(r"open\.spotify\.com/(album|track)/([a-zA-Z0-9]+)",
Platform.SPOTIFY),
# 애플뮤직
(r"music\.apple\.com/.+/(album|song)/.+?/(")",
Platform.APPLE_MUSIC),
# 기타...
]
링크 및 단축 URL 처리
파서는 10개 이상의 정규 표현식 패턴을 사용해 다양한 URL 형식을 매칭합니다. 스포티파이링크, 유튜브비 등 단축 URL은 HEAD 요청과 자동 리다이렉트 처리를 통해 원본 주소로 복원됩니다:
async def resolve_short_url(url: str) -> str:
async with aiohttp.ClientSession() as session:
async with session.head(
url, allow_redirects=True, timeout=5
) as resp:
return str(resp.url)
지원되는 콘텐츠 유형은 앨범, 트랙, 아티스트입니다. 트랙일 경우 자동으로 부모 발매물 위치를 확인합니다.
스포티파이 API 활용법
스포티파이 웹 API는 앨범의 external_ids.upc에 UPC를, 트랙 데이터에 ISRC를 제공합니다. 하지만 다음과 같은 도전 과제가 있습니다:
- 응답에서 UPC 누락 — 미국, 영국, 독일, 일본 등 다양한 시장에서 재시도 필요.
- 지역별 발매물에 대한 불안정한 UPC 검색 결과.
- 요청 제한: 분당 180회.
Redis 캐싱은 API 부하를 크게 줄여줍니다:
async def get_album_data(album_id: str) -> dict | None:
cache_key = f"album:{album_id}"
cached = await redis.get(cache_key)
if cached:
return json.loads(cached)
for market in ["US", "GB", "DE", "JP"]:
album = await spotify.get_album(album_id, market=market)
upc = album.get("external_ids", {}).get("upc")
if upc:
# 캐시 저장
await redis.set(cache_key, json.dumps(result), ex=86400)
return result
return None
비공식 API 활용: 얀덱스뮤직과 VK
공식 API가 없어 모바일 앱 트래픽을 분석해 엔드포인트를 역설계했습니다. 앨범 메타데이터에 UPC, 트랙 수준 데이터에 ISRC가 포함되어 있으며, 응답 형식이 예측 불가능하게 변경되기도 합니다(3개월 사이 2번). 따라서 지속적인 모니터링이 필요합니다.
발매물 버전 식별
봇은 하나의 ISRC에 연결된 모든 UPC를 찾아냅니다 — 싱글, 앨범, 컴필레이션 모두 포함됩니다. 이는 분배사 전환 시 스트리밍 기록을 유지하는 데 매우 중요합니다.
/full 명령어는 다음 정보를 반환합니다:
- 발매물의 모든 UPC 버전.
- 각 트랙의 ISRC.
- 레이블, 발매일, 장르.
- 트랙 BPM(스포티파이 오디오 특성 데이터 기반).
사용자 입력 처리
다양한 입력 방식을 지원합니다:
- 직접 링크(자동 파싱).
- 12~13자리 숫자(UPC 조회).
- 텍스트 쿼리(이름 검색 + 인라인 버튼).
예시: "upc 모로젠", 직접 URL, 비구조화된 문장 등.
학습된 교훈과 개선점
3개월 운영 통계:
- 월간 사용자: 500명.
- 평균 응답 시간: 1.5초(캐시 사용 시 0.3초).
- 성공률: 89%.
개선 제안:
- 데이터 검증을 위해 MusicBrainz 통합.
- 피크 부하 대응을 위한 메시지 큐 도입.
- API 가용성 점검 기능 추가.
아키텍처 통찰:
- 최소 두 개 이상의 데이터 소스를 사용해야 한다.
- 적극적인 캐싱 전략이 필수.
- 비공식 API는 기술적 부채를 초래한다.
핵심 요약:
- 파싱과 플랫폼 해상은 분리하면 유지보수가 쉬워진다.
- 시장 기반 재시도는 스포티파이 응답 미완성 문제 해결에 효과적.
- 요청 제한 상황에서는 Redis 캐싱이 필수.
- 하나의 ISRC에 여러 UPC가 존재하는 것은 아티스트에게 중요하다.
- 비공식 API는 반드시 매일 모니터링해야 한다.
— Editorial Team
아직 댓글이 없습니다.