[React] 서버 없이 음악 웹 플레이어 만들기

문정민·2023년 11월 15일

React

목록 보기
4/11
post-thumbnail

지난 번 포스팅 했던 음악 웹 플레이어 토이 프로젝트를 디벨롭하여, 서버 없이도 음악 파일을 업로드하여 재생목록을 만들 수 있는 기능을 추가했다. 이 기능은 전적으로 아래 블로그의 코드를 참고하여 기능을 구현했음을 미리 밝힌다.

👉 (reactjs)음악 플레이어 만들기(3-1) - 재생목록 제작

jsmediatags로 음악 파일의 메타데이터 추출하기

jsmediatags는 미디어 파일의 타이틀, 아티스트, 앨범, 앨범 아트 등의 정보를 추출하는데 도움을 주는 라이브러리이다. 설치 및 사용 방법은 아래 jsmediatags의 깃허브 리드미에 자세히 적혀있다.

👉 jsmediatags Github 바로가기

가져온 메타데이터를 변환하기

위 블로그의 코드에서는 jsmediatags 라이브러리를 통해 추출한 이미지 데이터를 Base 64 인코딩을 거쳐 문자열 형태로 변환한다. 그리고 인코딩된 문자열을 다시 웹에서 사용하기 위해 Blob 객체로 변환한다. 그리고 URL.createObjectURL 메서드를 사용하여 브라우저에서 해석 가능한 URL로 변환한다.

여기서 나는 Base64 인코딩과 Blob 객체를 처음으로 접했고, 이에 대해 간단히 정리해보고자 한다.

📝 Base64 Encode

✅ 이진 데이터(Binary Data)를 문자 코드에 영향을 받지 않는 공통 ASCII 영역의 문자열로만 이루어진 문자열로 바꾸는 인코딩 방식
✅ 데이터를 문자열로 바꾸어 텍스트 기반의 데이터로 사용할 수 있도록 하는 것
✅ 사용하는 이유? : 웹 환경에서 데이터를 쉽게 전송하고 사용하기 위함

웹 환경에서는 HTML, JSON 등 주로 텍스트 기반의 데이터 형식을 사용한다. 이진 데이터를 웹 환경에서 다루기 위해서 텍스트 형태로 변환을 하여 쉽게 사용할 수 있도록 하기 위함이다. 또한, 서버에 데이터를 전송할 때 JSON을 기반으로 한 API를 사용한다면, 이진 데이터를 문자열로 변환하여 데이터 손실 없이 데이터를 전송할 수 있다.

📝 Blob(Binary Large Object)

✅ 이미지, 사운드, 비디오와 같은 대용량의 바이너리 데이터를 담을 때 주로 사용. (반드시 미디어 데이터에만 사용하는 것은 아니며 바이너리로 표현 가능한 데이터에서 쓸 수 있다.)
✅JavaScript에서 Blob 객체를 사용할 때, 두 가지의 주요 파라미터가 있다.

1. blobParts

  • Blob 객체를 생성할 때 포함될 데이터
  • ArrayBuffer, ArrayBufferView, Blob, DOMString 등 다양한 타입의 데이터를 포함할 수 있는 배열
  • 텍스트 또는 바이너리 데이터, 또 다른 Blob 객체들을 이 배열에 넣어 사용할 수 있음.

2. options

  • Blob의 속성을 정의하는 객체로, 선택적으로 사용
  • 주로 설정하는 속성은 typeendings
  • type : "text/plain", "image/jpeg" 등의 MIME 타입을 설정
  • endings : \n을 포함하는 문자열 처리 방식을 정의, transparent(기본값)와 native 중 선택.
const data = new Blob(["Hello, world!"], { type: "text/plain" });

코드 개선

Base64와 Blob에 대해 이해를 하고 나서 다시 코드를 살펴보니, 한 가지 의문이 생겼다. jsmediatags로 가져온 앨범 커버 이미지는 이진 데이터이다. 서버로 전송하지 않는다면 굳이 Base64 인코딩을 할 필요없이 바로 Blob 객체로 만들면 되지 않을까?

이에 대한 GPT의 답변은 이러했다.

📢 네, 맞습니다. albumCover의 데이터가 이미 이진 데이터(binary data) 형태라면, 그 데이터를 직접 Blob 객체로 변환할 수 있습니다. base64 인코딩 과정은 실제로 필요하지 않을 수 있습니다.
(...중략)
하지만, 만약 데이터가 클라이언트 사이드에서만 처리되고 서버로 전송되지 않는다면, 이진 데이터를 직접 Blob 객체로 변환하는 것이 더 효율적입니다. base64 인코딩은 이진 데이터를 문자열로 변환하는 과정에서 추가적인 계산을 필요로 하며, 변환된 문자열은 원본 데이터보다 약 33% 더 큽니다. 따라서, 이진 데이터를 Blob으로 직접 다루면 메모리 사용량이 줄고 처리 속도가 개선됩니다.

이번 프로젝트는 서버로 데이터를 전송을 할 필요가 없으므로, 앨범 커버 이미지를 곧바로 Blob 객체로 변환해주는 방식으로 코드를 개선했다.

export const useHandleAudio = (setSongs) => {
  const handleAudio = useCallback(
    (event) => {
      const files = event.target.files;
      for (let i = 0; i < files.length; i += 1) {
        const file = event.target.files[i];
        const urlObj = URL.createObjectURL(file);
        const src = urlObj;
        const id = src.slice(-12);

        window.jsmediatags.read(file, {
          onSuccess: function (tag) {
            const title = tag.tags.title || "제목 없음";
            const artist = tag.tags.artist || "알 수 없는 음악가";
            let albumCover = tag.tags.picture;

            if (albumCover) {
              const albumCoverBlob = new Blob(
                [new Uint8Array(albumCover.data)],
                { type: albumCover.format }
              );
              albumCover = URL.createObjectURL(albumCoverBlob);
            } else {
              albumCover = basicImg;
            }

            const data = {
              id: id,
              artist: artist,
              song: title,
              image: albumCover,
              audio: src,
            };

            setSongs((prev) => [...prev, data]);
          },
          onError: function (error) {
            alert(JSON.stringify(error));
          },
        });
      }
    },
    [setSongs]
  );

  return handleAudio;
};

0개의 댓글