Velog
블로그 목록

무료 음악 스트리밍 서비스 "뮤지코" 개발 회고록

0
무료 음악 스트리밍 서비스 "뮤지코" 개발 회고록
reactexpress.jsfastapimongodb

시작하기에 앞서

오랜만에 벨로그를 다시 쓰는 것 같다.

그동안 딱히 벨로그에 남길 만큼 진행이 많이 된 프로젝트가 없었기도하고 귀찮았다

오랜만에 돌아온 벨로그의 주제는 바로바로,,,,,,

무료 음악 스트리밍 서비스 "뮤지코"

무료 음악 스트리밍에 드는 두가지 의문점

  1. 법적 문제(궁금증 해소, 스터디 프로젝트라 신경쓰지 않기로 함 / 비영리)
  2. 어떻게 만들었냐??????(이제부터 알아봅시다~)

개발 계기

개발 할 때 유튜브로 노래를 틀어 놓고 있었는데, 광고도 나오고 확실히 영상 플랫폼이라 음악을 듣기에는 어색한 부분이 많았다. 그러던 중 들었던 생각이 있는데,

iframe으로 웹에 영상을 가져와서 소리만 들려주면 음악 플랫폼 처럼 쓸 수 있을 것 같은데???

라고 생각했다.

그래서 일단 만들어 보기 시작했다.

주요 워크플로우

  1. naver VIBE의 차트 api, 신곡 api, 검색 api를 사용해 곡들을 가져온다.
  2. 만약 곡을 재생하려 한다면 제목과 아티스트 이름을 파이썬 서버로 보내 유튜브 검색을 한다.
  3. 반환된 영상 정보들의 videoId를 구하고 클라이언트로 반환한다.
  4. 받은 videoId와 나머지 vibe에서 제공하는 정보(앨범커버, 트랙ID, 제목, 아티스트)를 합쳐서 메인서버의 재생목록에 저장한다.
  5. 재생목록 속 저장된 데이터를 이용해 클라이언트에서 음악을 재생한다.

개발 언어, 프레임워크

  1. 웹 - 리액트 + 타입스크립트
  2. 메인 서버 - 익스프레스 + 자바스크립트 + 몽고디비 아틀라스
  3. 유튜브데이터 중계 서버 - FastAPI + 파이썬

일단 웹은 간단하게 만들었다.

react-player라는 라이브러리를 통해 유튜브 영상을 재생 할 수 있다.

여기에 다양한 컨트롤 기능을 제공해 이번 프로젝트에 제격이라 시작했다.

스타일링은 이모션으로 진행 했으며 반응형 처리까지 완료했다.

문제1

유튜브에서 임베딩을 막아놓은 영상은 재생 할 수가 없었다.

하지만 react-player에 onError속성이 임베드 에러가 나면 150을 반환해주는 것을 발견해서 onError에서 150이 뜨면 다른 videoId를 사용하는 방식으로 우회했다.

문제 2

원래 차트, 신곡, 검색 데이터 및 유튜브데이터 중계서버를 rapidapi에 있는 api들을 사용 했었는데, 무료는 크레딧이 너무 적고 돈을 쓰기에는 너무 비싸서 그냥 내가 직접 만들기로 했다.

메인 서버

메인 서버도 너무 무겁게는 만들기 싫어서 익스프레스와 몽고디비 아틀라스를 사용했다.

express.js

이번 프로젝트에서 express를 좀 제대로 써본 것 같다. express로 데이터 입출력 정도만 해봤지 이렇게 프로덕트를 만들어 본적은 없었기 때문에 간단하게 만들었더라도 배운 점이 많았다.

1. MVC패턴 적용하기

여기서 말하는 MVC는 모델과 컨트롤러 그리고 서비스 이 3개의 파트로 서버가 나뉘는 것을 말한다.

이전에 내가 했던 express.js는 그냥 app.js에 다 때려박는 코드였다면, 이번엔 규모가 좀 있는 프로젝트라 파일을 분리하기로 했다.

model은 몽구스의 스키마로 만들었고 controller는 express.Route()를 통해 구현했다.

service는 원래

javascript
app.get('/', async (req, res) => {
	//코드들
});

이렇게 적었던 것에서

javascript
const getMethod = async (req, res) => {
	//코드들
}

app.get('/', getMethod);

이렇게 변경했고 추가로 Route()를 사용해서

javascript
//router.js
const express = require('express');
const Router = express.Route();

const Router.get('/', userService);
const Router.post('/', boardService);
.
.
.

//app.js
const Router = require('./routers/router');
.
.
.
app.use('/api', Router);

이런식으로 사용했다.

확실히 코드가 좀 정형화 되니까 유지보수하긴 편했던 것 같다.

2. 몽고디비 아틀라스

몽고디비도 이번에 처음 써봤는데, 우리집 라즈베리파이에 서버를 설치하지 않고도(!!!) 원격 db를 사용할 수 있다는 점이 나에게 신선한 충격이었다.

그래서 이번 프로젝트에서 몽고디비 아틀라스를 적극 사용했다.

내가 느낀 몽고디비의 최대 장점은 json과 똑같은 형태라 로컬스토리지 쓰듯이 db를 운영할 수 있다는 것이었다.

javascript
//model/user.js
{
	queue: {
      type: [
        {
          title: String,
          artist: [
            {
              artistId: Number,
              artistName: String,
              isGroup: Boolean,
              imageUrl: String,
            },
          ],
          videoId: [String],
          trackId: Number,
          coverUrl: String,
        },
      ],
      default: [],
    },
}

유저 개개인이 가지고 있는 재생목록을 저장하는 부분인데, 만약 rdb였다면 이렇게 간단하게 일대다관계를 만들지 못했을 것이다. 웹 개발자인 나에게 json같이 서버를 짤 수 있다는 것이 너무 매력적인 부분이었다.

확실히 express로 서버를 만들어서 그런지 새로운 기능 하나 추가하는 것도 30분만 키보드 두들기면 디버깅까지 다 끝나서 생산성이 GOAT였다.

유튜브데이터 중계서버

이번 프로젝트에서 코드가 가장 짧고 규모도 가장 작지만 가장 중요한 서버이다.

1. innertube

innertube 깃허브

이런 모듈이 존재했다.

이 모듈 속에 키워드를 가지고 유튜브 검색을 해서 결과를 반환해주는 기능을 가지고 있었다.

무려 구글 로그인이나 api key없이 스크랩으로만 말이다. 미쳤다 진짜

데이터가 정형되어있지는 않아서 배열 속에 어떤 객체가 들어 있을진 모르지만 검색 결과의 영상 데이터가 담긴 객체는 생긴게 다 똑같아서 클라이언트로 반환해주기 전에 리스트 컴프리헨션을 써서 배열에 영상만 담기도록 했다.

python
onlyVideo = [obj for obj in filterdData if obj.get('videoRenderer') is not None]

찾아보니까 얘를 자바스크립트에서도 쓸 수 있는 다른 라이브러리가 있어서 메인 서버에서 다 돌릴까 고민중이다.!

2. FastAPI

확실히 좋긴 하다

얘도 메인서버와 마찬가지로 코드의 규모를 키울 필요가 없기 때문에 생산성이 좋은 FastAPI를 사용 했다.

얘는 auth도 필요 없고 해서 그냥 한 파일에 다 때려박을까 했는데

그래도 개발자라는 놈이 코드 정형화를 안해?

라는 생각이 들어서 model, service는 따로 디렉토리를 만들고 컨트롤러는 main.py에 넣었다.

배포

일단 모든 플랫폼에서 CI-CD는 구축해 두었다.

서버컴퓨터는 늘 그랬든 우리집 라즈베리파이를 사용했다.

1. 웹

웹은 그냥 nginx를 이용해 서브한다.

2. 메인 서버

pm2라는 라이브러리를 사용해 서버를 열고, nginx를 통해 접근할 수 있게 했다.

3. 유튜브데이터 중계 서버

pm2랑 비슷한 supervisor라는 모듈을 사용했다. 처음 사용해 봤는데, 서버를 직접 여는건 아니고 dockerfile처럼 어떤 명령어를 실행하고 어떤 파일을 사용할지를 알려주면 백그라운드에서 그 명령어를 돌려준다. 서버를 여는데에는 uvicorn을 사용했다. 얘도 마찬가지로 nginx를 이용해 접근할 수 있게 해주었다.

후기

이 모든 과정을 10일 안에 끝냈다. 사실 완전 완성은 아니고 0.9버전 정도 된다. (실사용 테스트 남았다)

암튼, 처음에 생각하고 있었던 기능들은 다 만들어서 만족은 한다.

생각보다 막히는 부분이 없어서 좀 놀랐고, 오랜만에 성장 했구나를 느꼈다.

추가로 친구들 한데 보여주니 되게 좋아해줘서 많이 고마웠다.

깃허브

뮤지코 웹 레포지토리

뮤지코 메인 서버 레포지토리

뮤지코 유튜브데이터 중계 서버 레포지토리

훈수는 언제나 환영

새 글 알림 받기

글이 마음에 드셨다면 블로그를 구독하고 새로운 소식을 받아보세요.

On this page