์๋ก
๊ฐ๋ฐ์๋ก์ ์ฐ๋ฆฌ๋ ๋๊ท๋ชจ ํ๋ซํผ์ด ์ ์ธ๊ณ์ ์ผ๋ก ๋ฉํฐ๋ฏธ๋์ด ๋ฐ์ดํฐ๋ฅผ ์ด๋ป๊ฒ ๊ด๋ฆฌํ๊ณ ๋ฐฐํฌํ๋์ง์ ๋ํด ํญ์ ํธ๊ธฐ์ฌ์ ๊ฐ์ต๋๋ค. ์ธ๊ณ ์ต๊ณ ์ ์ธ๋ก ์ฌ์ธ ๋ด์ ํ์์ค(The New York Times)์ ๋น๋์ค ๋ฐฐํฌ ์ํคํ
์ฒ๋ ๋จ์ํ ํ์ผ ํธ์คํ
์ด ์๋๋ผ, HLS(HTTP Live Streaming)๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํ๋ ๋ณต์กํ๊ณ ๋์ ์ธ ์ด๋ํฐ๋ธ ์คํธ๋ฆฌ๋ฐ ์์คํ
์ ์ฑํํ๊ณ ์์ต๋๋ค.
์ฐ๊ตฌ์๋ ๊ฐ๋ฐ์๋ค์๊ฒ NYTimes์ ๊ณ ํ์ง ๋ด์ค ์์์ ์์นด์ด๋ธํ๋ ๊ฒ์ ๊ธฐ์ ์ ์ผ๋ก ํฐ ์๋ฏธ๊ฐ ์์ต๋๋ค. ๊ทธ๋ฌ๋ DRM(๋์งํธ ์ ์๊ถ ๊ด๋ฆฌ)์ ๊ฐํ์ ์คํธ๋ฆฌ๋ฐ ํ๋กํ ์ฝ์ ํํธํ๋ก ์ธํด ์ด๋ฌํ ๋ฆฌ์์ค๋ฅผ ํจ์จ์ ์ผ๋ก ์ถ์ถํ๋ ์ง์
์ฅ๋ฒฝ์ ์ ์ ๋์์ง๊ณ ์์ต๋๋ค. ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ์ ๋ NYTimes ๋น๋์ค ๋ค์ด๋ก๋๋ฅผ ๊ฐ๋ฐํ์ต๋๋ค. ๋ณธ ์ํฐํด์์๋ ๊ทธ ์ด๋ฉด์ ์จ๊ฒจ์ง ๊ณตํ์ ๊ตฌํ, ์ฆ HLS ํ๋กํ ์ฝ ์ญ๊ณตํ, ๋์ ํ ํฐ ๊ฒ์ฆ ๋ฃจํ, ๊ทธ๋ฆฌ๊ณ ์๋ฒ ์ฌ์ด๋ ๋ฌด์์ค ๋จธ์ฑ(Lossless Muxing)์ ๋ํด ์์ธํ ์ค๋ช
ํ๊ณ ์ ํฉ๋๋ค.
1. ๋ฏธ๋์ด ๋ฐฐํฌ ํ๋กํ ์ฝ์ ์งํ: MP4์์ HLS๋ก
์ด๊ธฐ ์น ๋น๋์ค ๋ฐฐํฌ ๋ฐฉ์์ ๋งค์ฐ ๋จ์ํ์ต๋๋ค.
- Master Playlist(๋ง์คํฐ ํ๋ ์ด๋ฆฌ์คํธ): ๋ค์ํ ํด์๋(์: 480p, 720p, 1080p)์ ๋์ํ๋ ํ์ ํ๋ ์ด๋ฆฌ์คํธ๋ฅผ ํฌํจํฉ๋๋ค.
- Media Playlist(๋ฏธ๋์ด ํ๋ ์ด๋ฆฌ์คํธ): ํน์ ํด์๋์ ๋ํด ๋น๋์ค ์ธ๊ทธ๋จผํธ์ ์ํ์ค๋ฅผ ๋์ดํฉ๋๋ค. ๊ฐ ์ธ๊ทธ๋จผํธ์ ๊ธธ์ด๋ ๋ณดํต 2์ด์์ 6์ด ์ฌ์ด์ ๋๋ค. ๊ธฐ์ ์ ๋์ : ์ถ์ถ ์์ง์ .m3u8์ ํธ๋ฆฌ ๊ตฌ์กฐ๋ฅผ ์ฌ๊ท์ ์ผ๋ก ํด์ํ๋ ๊ธฐ๋ฅ์ ๊ฐ์ถ์ด์ผ ํฉ๋๋ค. ํนํ ์ ๋์ญํญ์ฉ ์ ํ์ง ๋ฒ์ ์ด ์๋, ์ฌ์ฉ์๊ฐ ์๋ณธ ํ์ง์ ์ป์ ์ ์๋๋ก ์ต๊ณ ๋นํธ๋ ์ดํธ(Highest Bitrate) ํธ๋์ ์๋์ผ๋ก ์๋ณํ๊ณ ๊ฒฉ๋ฆฌํด์ผ ํฉ๋๋ค.
2. ์ญ๊ณตํ: ๋์ ์ธ์ฆ ์ฅ๋ฒฝ ๋ํํ๊ธฐ
NYTimes๋ ๋น๋์ค API์ ๋ํด ๋ค์ค ๋ณดํธ ๊ณ์ธต์ ์ ์ฉํฉ๋๋ค. ํ์ค curl ๋ช
๋ น์ด๋ก ๋ด๋ถ ๋ฏธ๋์ด ์ธํฐํ์ด์ค์ ์์ฒญ์ ๋ณด๋ด๋ฉด ๋๊ฐ 403 Forbidden ๋๋ 401 Unauthorized ์ค๋ฅ๊ฐ ๋ฐ์ํฉ๋๋ค.
์๋ช
๋ฉ์ปค๋์ฆ ๋ฐ ์ธ์
๊ด๋ฆฌ
NYTimes ์น ํด๋ผ์ด์ธํธ๋ ๋ณต์กํ ์ธ์ฆ ๋ก์ง์ ์์กดํฉ๋๋ค.
โข API Key ๊ฒ์ฆ: ๋๋
ํ๋ JavaScript ๋ฒ๋ค(JS Bundles) ๋ด๋ถ์ ์จ๊ฒจ์ ธ ์์ต๋๋ค.
โข ๋์ ์๋ช
(Signatures): ๊ฐ ์ธ๊ทธ๋จผํธ ์์ฒญ์ ๋ํด ์์ฑ๋๋ ์ํจ์ฑ ์๋ ํด์๊ฐ์
๋๋ค.
์์ง๋์ด๋ง ๊ตฌํ: ์ ํฌ ๋ฐฑ์๋๋ ์๊ฐ ์น์ ํ ์ธ์
ํ(Self-healing Session Pool)์ ์ ์งํฉ๋๋ค. ํ ํฐ ๋ง๋ฃ๋ ์๋ ์ ํ(Rate Limiting)์ผ๋ก ์ธํด ์์ฒญ์ด ์คํจํ ๊ฒฝ์ฐ, ์์ง์ ์๋์ผ๋ก ํ๋ ๋ธ๋ผ์ฐ์ ์ 'ํธ๋์
ฐ์ดํฌ' ํ๋ฆ์ ์๋ฎฌ๋ ์ด์
ํฉ๋๋ค. ์ฌ๊ธฐ์๋ ์ต์ํ์ ๋ธ๋ผ์ฐ์ ํ๊ฑฐํ๋ฆฐํ
(Fingerprinting)์ด ํฌํจ๋์ด ๋ด ๊ฐ์ง ์์คํ
์ ์ฐํํ๋ฉด์๋, ๊ณ ๋น๋ ๋ณ๋ ฌ ์ฒ๋ฆฌ๋ฅผ ์ง์ํ ์ ์๋ ๊ฒฝ๋์ฑ์ ์ ์งํฉ๋๋ค.
3. ๋ฐฑ์๋ ์ํคํ ์ฒ: Async I/O ๊ธฐ๋ฐ ๊ณ ๊ฐ์ฉ์ฑ ์ฒ๋ฆฌ
๊ธ๋ก๋ฒ ๋ค์ด๋ก๋ ์์ฒญ์ ๊ฐ๋นํ๊ธฐ ์ํด, nytimes_downloader_ko์ ๋ฐฑ์๋๋ ์ ํต์ ์ธ ๋ธ๋กํน ์์ฒญ ๋ชจ๋ธ์ ๋ฒ๋ฆฌ๊ณ Python Asyncio + Httpx ๊ธฐ๋ฐ์ ์์ ๋น๋๊ธฐ ์คํ์ ์ฑํํ์ต๋๋ค.
์ ๋น๋๊ธฐ์ธ๊ฐ?
๋น๋์ค ์ถ์ถ์ ๋ณธ์ง์ ์ผ๋ก I/O ๋ฐ์ด๋(I/O-bound) ์์
์
๋๋ค. ํ๋์ ์ฌ์ฉ์ ์์ฒญ์ ๋ค์๊ณผ ๊ฐ์ ๊ณผ์ ์ ๊ฑฐ์นฉ๋๋ค.
- ํ์ด์ง HTML์ ํ์ฑํ์ฌ ๋ฉํ๋ฐ์ดํฐ ์ถ์ถ.
- ๋ด๋ถ REST ๋๋ GraphQL ์ธํฐํ์ด์ค๋ฅผ ์ฟผ๋ฆฌํ์ฌ ๋ฏธ๋์ด ์ค์ ํ๋.
- ๋คํธ์ํฌ๋ฅผ ํตํด ๋ค๋จ๊ณ .m3u8 ํ์ผ์ ์ฌ๊ท์ ์ผ๋ก ์คํฌ๋ ์ดํ. ๋๊ธฐ ๋ชจ๋ธ์์๋ ์์ปค ํ๋ก์ธ์ค๊ฐ ๋คํธ์ํฌ ์๋ต์ ๊ธฐ๋ค๋ฆฌ๋ ๋์ ์ ํด ์ํ๊ฐ ๋ฉ๋๋ค. ๋ฐ๋ฉด asyncio๋ฅผ ์ฌ์ฉํ๋ฉด ๋จ์ผ ํ๋ก์ธ์ค๋ก ์์ฒ ๊ฐ์ ๋ณ๋ ฌ ์ถ์ถ ์์ ์ ๊ด๋ฆฌํ ์ ์์ด, ์๋ฒ ํ๋์จ์ด ๋น์ฉ์ ๊ทน์ ์ผ๋ก ๋ฎ์ถ๋ฉด์ ์๋ต ์๊ฐ์ ๋จ์ถํ ์ ์์ต๋๋ค.
4. ์๋ฒ ์ฌ์ด๋ ์ฒ๋ฆฌ: FFmpeg๋ฅผ ์ด์ฉํ ๋ฌด์์ค ๋จธ์ฑ
๋ชจ๋ HLS ์ธ๊ทธ๋จผํธ๋ฅผ ํ์ฑํ ํ, ์ต์ข
์ ์ผ๋ก ์ฌ์ฉ์์๊ฒ ํ๋์ MP4 ํ์ผ์ ์ ๋ฌํด์ผ ํฉ๋๋ค. ์ฌ์ฉ์์๊ฒ ์๋ฐฑ ๊ฐ์ TS ์กฐ๊ฐ์ ์๋์ผ๋ก ๋ค์ด๋ก๋ํ๊ฒ ํ๋ ๊ฒ์ ์ต์
์ UX์
๋๋ค.
์คํธ๋ฆผ ๋ณต์ฌ(Stream Copying) vs ์ธ์ฝ๋ฉ(Transcoding)
์ ํฌ๋ FFmpeg๋ฅผ ํ์ดํ๋ผ์ธ์ ํตํฉํ์ฌ ์ค์๊ฐ ๋จธ์ฑ(๊ฒฐํฉ)์ ์ํํฉ๋๋ค. ์ฌ๊ธฐ์ ๊ฐ์ฅ ์ค์ํ ์ต์ ํ๋ ์คํธ๋ฆผ ๋ณต์ฌ(Stream Copying)๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์
๋๋ค.
Bash
ffmpeg -i "concat:file1.ts|file2.ts|..." -c copy -map 0โ๏ธ0 -map 1๐
ฐ๏ธ0 output.mp4
๊ธฐ์ ์ ํต์ฐฐ: -c copy ํ๋๊ทธ๊ฐ ํต์ฌ์
๋๋ค. ์ด๋ FFmpeg์๊ฒ ํ์ ํฝ์
์ธ์ฝ๋ฉ์ ๊ฑด๋๋ฆฌ์ง ์๊ณ ๋ฐ์ดํฐ ํจํท์ TS ์ปจํ
์ด๋์์ MP4 ์ปจํ
์ด๋๋ก ์ด๋๋ง ์ํค๋๋ก ์ง์ํฉ๋๋ค. ๋๋ถ์ ์ฒ๋ฆฌ๋ ๊ฑฐ์ ์ฆ์ ์๋ฃ๋๋ฉฐ, CPU ์ง์ฝ์ ์ธ ํธ๋์ค์ฝ๋ฉ ์์ด 100% ์๋ณธ ํ์ง์ ์ ์งํ ์ ์์ต๋๋ค. ํ์ง ์ ํ(Generation Loss)๊ฐ ์ ํ ๋ฐ์ํ์ง ์์ต๋๋ค.
5. ํ๋ก ํธ์๋ ์ต์ ํ: Utility-First ๋๊ตฌ ์ฒ ํ
ํ๋ก ํธ์๋ ๋์์ธ์ '์ ๋ก ๋ฒ๋ค' ์์น์ ๋ฐ๋ฆ
๋๋ค.
โข Vanilla JS ๊ตฌํ: ๋ฌด๊ฑฐ์ด ํ๋ ์์ํฌ๋ฅผ ๋ฐฐ์ ํ์ฌ First Contentful Paint(FCP)๋ฅผ 1์ด ๋ฏธ๋ง์ผ๋ก ๋จ์ถํ์ต๋๋ค.
โข PWA ์ง์: ์น ์ฌ์ดํธ๋ ์ ์ง์ ์น ์ฑ(PWA) ์ฌ์์ ์ง์ํ์ฌ ๋ชจ๋ฐ์ผ ๋ฐ ๋ฐ์คํฌํฑ ํ๊ฒฝ์์ ๋ค์ดํฐ๋ธ ์ฑ์ ๊ฐ๊น์ด ์ฌ์ฉ์ ๊ฒฝํ์ ์ ๊ณตํฉ๋๋ค.
โข ๋ณด์์ฑ: ๋ชจ๋ ๋ถ์ ๋ก์ง์ ์๋ฒ ์ฌ์ด๋์์ ์๊ฒฐ๋๋ฏ๋ก, ์ฌ์ฉ์๋ ๊ฐ์ธ์ ๋ณด ์นจํด ์ฐ๋ ค๊ฐ ์๋ ์ํํ ๋ธ๋ผ์ฐ์ ํ์ฅ ํ๋ก๊ทธ๋จ์ ์ค์นํ ํ์๊ฐ ์์ต๋๋ค.
6. ์ค๋ฆฌ์ ๋ฒ ์คํธ ํ๋ํฐ์ค
์ด๋ฌํ ๋๊ตฌ๋ฅผ ๊ตฌ์ถํ ๋๋ ๊ธฐ๋ฅ์ฑ๊ณผ ๊ท์ ์ค์ ์ฌ์ด์ ๊ท ํ์ด ํ์ํฉ๋๋ค.
โข ๊ฐ์ธ์ ๋ณด ์ฐ์ : ์ ํฌ๋ ์ฌ์ฉ์์ ๋น๋์ค ํ์ผ์ ์๊ตฌ์ ์ผ๋ก ์ ์ฅํ์ง ์์ต๋๋ค. ์์ ๋ฐ์ดํฐ๋ ์ ๋ฌ์ด ์๋ฃ๋๋ ์ฆ์ ํ๊ธฐ๋ฉ๋๋ค.
โข ์๋ ์ ํ ์ธ์ง: ์์คํ
๋ด๋ถ์ ํ ๊ด๋ฆฌ ๊ธฐ๋ฅ์ ๊ฐ์ถ์ด NYTimes์ ๊ณต์ ์ธํ๋ผ์ ๋ถํ์ํ ๋ถํ๋ฅผ ์ฃผ์ง ์๋๋ก ์ค๊ณ๋์์ต๋๋ค.
๊ฒฐ๋ก
๊ณ ์ฑ๋ฅ ๋ค์ด๋ก๋๋ฅผ ๊ตฌ์ถํ๋ ๊ฒ์ ๋จ์ํ ํฌ๋กค๋ง ์์
์ด ์๋๋ผ ํ๋์ ์ธ ์น ํ๋กํ ์ฝ, API ์ญ๊ณตํ, ๊ทธ๋ฆฌ๊ณ ํจ์จ์ ์ธ ๋ฏธ๋์ด ์ฒ๋ฆฌ์ ๋ํ ๊น์ ์ค์ฒ์
๋๋ค. HLS ํ์ฑ ๋ก์ง์ ์ต์ ํํ๊ณ ๋น๋๊ธฐ ๋ฐฑ์๋ ์ํคํ
์ฒ๋ฅผ ํ์ฉํจ์ผ๋ก์จ, ์ ํฌ๋ ์ํํ 1080p ๋น๋์ค ์ถ์ถ ๊ฒฝํ์ ๊ตฌํํ์ต๋๋ค.
๊น๋ํ๊ณ ๊ด๊ณ ๊ฐ ์์ผ๋ฉฐ ๊ธฐ์ ์ ์ผ๋ก ๊ฒฌ๊ณ ํ ๋ฐฉ์์ผ๋ก ๋ด์ ํ์์ค์ ๋น๋์ค ์ฝํ
์ธ ๋ฅผ ์์นด์ด๋ธํ๋ ค๋ ๊ฐ๋ฐ์๋ผ๋ฉด ์ ํฌ ๋๊ตฌ๋ฅผ ์ฌ์ฉํด ๋ณด์๊ธฐ ๋ฐ๋๋๋ค.
๐ ํ๋ก์ ํธ ๋งํฌ: ๋ด์ ํ์์ค ๋น๋์ค ๋ค์ด๋ก๋(ํ๊ตญ์ดํ)
๊ธฐ์ ์คํ ์์ฝ:
โข Backend: Python / Django / Redis / FFmpeg
โข Architecture: Asyncio / Distributed Crawling
โข Frontend: HTML5 / Tailwind CSS / Vanilla JS
โข Infrastructure: Cloudflare / Docker / Nginx
HLS ํ์ฑ ๋ก์ง์ด๋ FFmpeg ์คํธ๋ฆผ ์กฐ์์ ๋ํด ๊ถ๊ธํ ์ ์ด ์๋ค๋ฉด ์๋ ๋๊ธ์ฐฝ์์ ํจ๊ป ํ ๋ก ํด ๋ด
์๋ค!













