안녕하세요, 개발자 여러분! 오늘은 제가 최근에 작업한 YouTube Shot이라는 크롬 확장 프로그램을 소개하고, 개발 과정에서 겪었던 경험과 학습 내용을 공유하려고 합니다. 이 확장 프로그램은 유튜브 영상을 보다가 마음에 드는 장면을 바로 캡처해서 저장할 수 있는 툴인데요. 기술적으로 어떻게 구현했는지, 그리고 어떤 문제를 해결했는지 자세히 설명드릴게요.
1. 왜 만들었나요?
평소 유튜브를 보면서 "이 장면 정말 멋진데 저장하고 싶다!"라는 생각을 종종 하곤 했습니다. 그런데 매번 전체 화면을 캡처하거나 별도의 프로그램을 사용하는 게 번거롭더라고요. 그래서 간단하게 클릭 한 번으로 유튜브 영상의 특정 순간을 캡처하고 저장할 수 있는 도구를 만들어보자는 생각이 들었습니다. 그렇게 탄생한 게 YouTube Shot입니다.
2. 핵심 기능
A. 영상 스크린샷 캡처
가장 중요한 기능은 현재 재생 중인 유튜브 영상의 프레임을 캡처하는 겁니다. 예를 들어, 특정 장면에서 멈춘 상태로 버튼을 누르면 그 장면을 이미지로 저장할 수 있습니다.
B. 이미지 다운로드
캡처된 이미지는 Base64 형식으로 변환되어 사용자의 컴퓨터에 PNG 파일로 저장됩니다. 사용자가 원하는 이름으로 저장할 수도 있고, 나중에 쉽게 공유할 수도 있습니다.
C. 사용자 친화적인 UI
확장 프로그램 아이콘을 클릭하면 즉시 스크린샷이 찍히고, 결과물은 새 탭이나 팝업에서 확인할 수 있도록 설계했습니다. 최대한 직관적이고 간단하게 만들려고 노력했어요.
3. 기술적 구현
이제 본격적으로 코드와 기술적인 부분을 살펴볼게요. 개발하면서 가장 신경 썼던 부분은 "유튜브 페이지와 어떻게 상호작용할 것인가"였습니다. 아래에서 주요 기능별로 설명드리겠습니다.
A. 비디오 프레임 캡처
스크린샷의 핵심은 유튜브 비디오 플레이어의 현재 프레임을 캡처하는 거예요. 이를 위해 HTML5 <canvas>
요소를 활용했습니다.
1. Canvas로 비디오 프레임 캡처하기
function captureVideoFrame(videoElement) {
const canvas = document.createElement("canvas");
const context = canvas.getContext("2d");
// 비디오 크기에 맞게 Canvas 설정
canvas.width = videoElement.videoWidth;
canvas.height = videoElement.videoHeight;
// 비디오 프레임을 Canvas에 그림
context.drawImage(videoElement, 0, 0, canvas.width, canvas.height);
// Canvas 데이터를 Base64로 변환
return canvas.toDataURL("image/png");
}
Canvas는 비디오 요소의 현재 프레임을 정확히 복사할 수 있어서 정말 유용했어요. toDataURL
메서드를 사용해 이미지를 Base64 형식으로 변환하면, 이 데이터를 다운로드하거나 다른 방식으로 활용할 수 있답니다.
2. 비디오 요소 찾기
유튜브 페이지에서 비디오 요소를 선택하는 것도 중요했어요. 유튜브는 HTML 구조가 동적으로 바뀌기 때문에, 비디오 요소의 클래스 이름이나 ID를 분석해야 했습니다.
const videoElement = document.querySelector("video.html5-main-video");
if (!videoElement) {
console.error("비디오 요소를 찾을 수 없어요!");
return;
}
B. 스크립트 주입
유튜브 페이지에서는 직접 DOM을 조작할 수 없기 때문에, Chrome Extensions API를 사용해 스크립트를 주입해야 했습니다. 여기서는 chrome.scripting.executeScript
를 활용했어요.
1. 백그라운드 스크립트에서 실행
chrome.action.onClicked.addListener((tab) => {
chrome.scripting.executeScript({
target: { tabId: tab.id },
func: captureVideoFrame,
args: ["video.html5-main-video"],
});
});
백그라운드 스크립트에서 executeScript
를 호출하면, 유튜브 페이지 내부에서 captureVideoFrame
함수를 실행할 수 있어요. 이렇게 하면 유저가 확장 프로그램 아이콘을 클릭했을 때 바로 스크린샷이 찍히게 됩니다.
2. 메시지 전달
또 다른 방법으로는 chrome.runtime.sendMessage
를 사용해 백그라운드와 콘텐츠 스크립트 간에 메시지를 주고받는 방법도 있죠.
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.action === "capture") {
const videoElement = document.querySelector("video.html5-main-video");
const imageData = captureVideoFrame(videoElement);
sendResponse({ image: imageData });
}
});
이렇게 메시지를 통해 데이터를 주고받으면, 좀 더 유연하게 기능을 확장할 수 있습니다.
C. 이미지 다운로드
캡처된 이미지를 다운로드하는 기능도 구현했어요. Base64 데이터를 Blob으로 변환한 뒤, 링크를 생성해 다운로드하도록 처리했답니다.
1. Base64를 Blob으로 변환
function base64ToBlob(base64, mimeType) {
const byteString = atob(base64.split(",")[1]);
const arrayBuffer = new ArrayBuffer(byteString.length);
const uint8Array = new Uint8Array(arrayBuffer);
for (let i = 0; i < byteString.length; i++) {
uint8Array[i] = byteString.charCodeAt(i);
}
return new Blob([uint8Array], { type: mimeType });
}
2. 이미지 다운로드
function downloadImage(base64, filename) {
const blob = base64ToBlob(base64, "image/png");
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = filename || "screenshot.png";
a.click();
URL.revokeObjectURL(url); // 메모리 정리
}
이렇게 하면 사용자가 원하는 이름으로 이미지를 저장할 수 있어요.
4. 어려웠던 점과 해결 방법
개발하면서 몇 가지 어려운 점이 있었는데요, 그중에서도 특히 유튜브 페이지의 동적 구조와 Chrome Extensions API의 제약이 큰 도전이었습니다.
A. 유튜브 페이지의 동적 구조
유튜브는 SPA(Single Page Application)로 구현되어 있어서, 페이지가 완전히 새로 고침되지 않아요. 그래서 비디오 요소를 찾거나 DOM을 조작할 때 주의가 필요했습니다. 이 문제는 MutationObserver
를 사용해 해결했어요.
const observer = new MutationObserver((mutationsList) => {
for (const mutation of mutationsList) {
if (mutation.type === "childList") {
const videoElement = document.querySelector("video.html5-main-video");
if (videoElement) {
console.log("비디오 요소 감지됨!");
observer.disconnect(); // 감지 중단
}
}
}
});
observer.observe(document.body, { childList: true, subtree: true });
B. Chrome Extensions API 제약
Manifest V3에서는 background.js
가 Service Worker로 동작하기 때문에, 지속적인 상태 관리가 어렵더라고요. 그래서 필요한 경우만 스크립트를 주입하거나 메시지를 보내는 방식으로 해결했습니다.
5. 마무리
이번 프로젝트를 통해 Chrome Extensions 개발과 HTML5 Canvas의 활용법을 배울 수 있었습니다. 특히 유튜브와 같은 동적 웹사이트에서 확장 프로그램을 구현하는 건 쉽지 않았지만, 그만큼 배운 것도 많았어요. 앞으로도 이런 작은 도구들을 하나씩 만들어서 공유하고 싶네요!
혹시 궁금한 점이 있다면 댓글로 남겨주세요. 함께 이야기 나누면서 더 발전할 수 있으면 좋겠어요 😊
'Review' 카테고리의 다른 글
TikTok Screenshot: 틱톡 영상 캡쳐 크롬 확장 앱 개발 후기 (1) | 2025.04.07 |
---|---|
Insta Screenshot 크롬 확장앱 개발 일지 (1) | 2025.04.06 |
RegExer: 정규 표현식 기반의 웹 페이지 텍스트 분석 도구 개발일지 (0) | 2025.04.03 |
Readers 크롬 앱 개발 일지 (4) | 2025.03.27 |
멀티서치 크롬확장앱 개발 일지 (2) | 2025.03.22 |