본 포스팅은 음악을 쉽게 담을 수 있게 도와주는 'Sqoop 스쿱' 프로젝트의 트러블 슈팅 내용을 기록했습니다.
스쿱 서비스는 1차 추출(얕은 추출) 단계에서 Description, Comment List 등의 문자열을 받아와 정규표현식으로 변환하고, 이를 활용해 음악 리스트를 추출합니다.
기존의 음악 리스트를 추출 할 때 사용하는 정보는 오로지 타임스탬프 뒤에 따라오는 제목 및 아티스트 titleOrArtists
정보로, 이는 정확도 관련 이슈를 만들었습니다. 03:56 - Sunflower
라는 문자열을 이용해 MusicKit
으로 검색하는 상황을 예시로 들어보겠습니다. MusicKit
의 검색 필드엔 ‘Sunflower’가 사용되고, 이는 다음과 같은 리스트를 반환합니다.
외부 검색어를 받아 로직을 수행하는 입장에서, ‘Sunflower’라는 문자열이 제목을 뜻하는지, 아티스트를 뜻하는지 혹은 모두 포함하고 있는지 알 수 없기 때문에 MusicKit
은 관련성 높은 곡을 기준으로 리스트를 반환하게 됩니다. 관련성이 높다는 것은, 찾으려는 곡과 일치할 확률 또한 높다고 가정할 수 있었기에 첫번째 곡을 반환하는 것으로 비즈니스 로직을 구현할 수 있었습니다.
하지만 관련성이 높은 곡이 항상 영상 속 곡과 일치하는 것은 아니었습니다. 마이너한 음악, 원본 문자열이 복잡한 경우 등의 엣지 케이스는 존재했고 이는 리스트 내 2번째, 3번째 등에 위치해 제목은 비슷하지만 완전히 다른 곡을 추출하는 문제로 이어졌습니다.
팀 내 논의 후 두가지 개선 방향성을 찾을 수 있었습니다.
- AI를 이용한 제목 및 아티스트 판별
- 다른 메타 데이터를 필터링에 사용
AI를 활용한 첫번째 방법은 정확도를 크게 끌어올릴 수 있을 것으로 기대했지만 짧은 프로젝트 기간, AI 사용 비용 등의 문제로 보류되었습니다. 메타 데이터를 활용한 두번째 방법의 경우, 검색어 정확도에 영향을 줄 수 있는 정보가 무엇인지 식별하는 것이 우선적으로 필요했고, 그 중 음악 길이 정보를 선정할 수 있었습니다.
제목 및 아티스트 + 그와 가장 근사한 길이의 음악 메타데이터를 조합해 기존 보다 높은 정확도의 음악 리스트 추출에 성공할 수 있을 것이라 판단했고, 음악 길이를 계산하기 위한 로직을 구현했습니다.
음악 길이를 계산하기 위해 문자열 내부의 타임 스탬프(03:56
, 01:45:26
등) 값을 활용했습니다. 이전 곡의 타임스탬프와 다음 곡의 타임스탬프의 시간 차를 이용해 이전 곡의 ‘음악 추정 시간’ estimateDuration
을 계산할 수 있었습니다.
/// 음악 추정 시간 계산 로직
for (index, timeSeconds) in timeSecondsList.enumerated() {
if index == 0 { continue }
// 다음 곡의 타임 스탬프 - 이전 곡의 타임 스탬프 = 이전 곡의 음악 추정 시간
let estimatedDuration = timeSeconds - timeSecondsList[index - 1]
musicInfoList[index - 1].estimateDuration = estimatedDuration
}
다음 곡의 타임스탬프 값을 이용해 이전 곡의 추정 시간을 구하는 위 코드는, 가장 마지막 곡의 추정 시간은 구할 수 없었습니다. 이를 해결하기 위해 Youtube Data API에서 제공하는 ‘영상 전체 길이'를 활용했습니다.
/// 음악 리스트의 마지막 추정 길이를 계산합니다.
func calcLastMusicEstimateDuration(from ytPlaylist: YTPlaylist) -> YTPlaylist {
// 음악 리스트의 개수가 부족하면 그대로 반환
guard ytPlaylist.musicInfoList.count > 1 else { return ytPlaylist }
// 마지막 음악 추정 길이 계산 로직
var musicInfoList = ytPlaylist.musicInfoList
let totalDuration = ytPlaylist.videoInfo.duration
let lastEstimateDuration = totalDuration - ytPlaylist.musicInfoList.reduce(0) { $0 + $1.estimateDuration }
musicInfoList[musicInfoList.count - 1].estimateDuration = lastEstimateDuration
return YTPlaylist(
playlistId: ytPlaylist.playlistId,
urlType: ytPlaylist.urlType,
videoInfo: ytPlaylist.videoInfo,
musicInfoList: musicInfoList
)
}
해당 로직 적용 후, 눈에 띄게 정확도를 개선할 수 있었습니다. 100%로 정확도를 끌어올릴 수는 없었지만, 추가 메타데이터를 활용해 이전에 실패하던 케이스의 곡들을 식별할 수 있었습니다.
음악 추정 길이는 영상 중간중간의 비어있는 시간, 문자열 작성자의 정확도에 크게 의존하는 형태입니다. 하지만 이를 활용했을 때 정확도 개선의 긍정적 효과가 문제점이 가져올 수 있는 부정적 효과보다 크다 판단했고, 최종 프로덕트에도 해당 비즈니스 로직을 적용하게 되었습니다.
관련 PR
- [PR/#92] YTMusicInfo 음악 추정 길이 로직 구현 - https://github.com/DeveloperAcademy-POSTECH/2024-MacC-M14-Medio/pull/93
- [PR/#100] MKCatalogSearcher 검색 정확도 향상 - https://github.com/DeveloperAcademy-POSTECH/2024-MacC-M14-Medio/pull/107
'iOS > 프로젝트 일지' 카테고리의 다른 글
데이블럭 회고 - 하루 24개의 블럭을 가치있게 쌓아나가는 방법 (0) | 2025.03.09 |
---|---|
캐플 리팩토링 네 번째 이야기 - Repository 모듈 만들기 (0) | 2025.02.24 |
스쿱 트러블 슈팅 - API로부터 도메인을 안전하게 지키기 (1) | 2025.02.17 |
스쿱 트러블 슈팅 - 유연하고 구조적인 정규표현식 만들기 (0) | 2025.02.17 |
캐플 리팩토링 세 번째 이야기 - 트러블 슈팅 (2) | 2025.02.07 |