YouTube ๊ด‘๊ณ , ๋ฉˆ์ถฐ!! ๐Ÿ–๐Ÿป(2)

trevor.phยท2021๋…„ 6์›” 20์ผ
3

์˜์‹์˜ํ๋ฆ„๋Œ€๋กœ

๋ชฉ๋ก ๋ณด๊ธฐ
2/4
post-thumbnail

[0] TL;DR

๊ด‘๊ณ ๊ฐ€ ๋œจ๋Š” <video> element๋ฅผ ์žก์•„ currentTime=1000 ๊ฐ’์„ ์ค€๋‹ค

[1] ๋„์ž… ๊ณ„๊ธฐ

์ง€๋‚œ ๋ฒˆ์— ๋งŒ๋“  chrome extension์€ ์ž˜ ๋™์ž‘ํ–ˆ์œผ๋‚˜ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฒฝ์šฐ ๊ทธ์ € ๊ด‘๊ณ ๋ฅผ ์‹œ์ฒญํ• ์ˆ˜ ๋ฐ–์— ์—†์—ˆ๋‹ค

  • ๋ฌด์กฐ๊ฑด ๋ณผ์ˆ˜๋ฐ–์— ์—†๋Š” 5+์ดˆ์งœ๋ฆฌ ๊ด‘๊ณ 
  • 10๋ถ„ ๊ฐ„๊ฒฉ์œผ๋กœ ๋œจ๋Š” ๊ด‘๊ณ (๊ธด ์˜์ƒ)

๊ทธ๋ฆฌ๊ณ  setInterval() ์„ ํ†ตํ•ด 1์ดˆ๋งˆ๋‹ค pollingํ•˜๋Š” ๋ฐฉ์‹์€ ๊ตฌํ˜„ํ•˜๊ธฐ์—๋Š” ํŽธํ•˜๋‚˜ ์ข€ ๊ตฌ๋ฆฐ ๋Š๋‚Œ์ด ๋“ค์—ˆ๋‹ค. ์•„์ง ์ข€ ๋” ์ž˜ ํ• ์ˆ˜ ์žˆ๋‹ค...

[2] ์‹œ๋„ํ–ˆ๋˜ ๋ฐฉ๋ฒ•โ›๏ธ

developer tool ์„ ํ†ตํ•ด youtube ์†Œ์Šค์ฝ”๋“œ๋ฅผ ๋””๋ฒ„๊น…ํ•˜๋ฉฐ skip() ๊ฐ™์€ ๊ฐœ๊ฟ€๐Ÿ˜‹ ํ•จ์ˆ˜๊ฐ€ ์žˆ๋Š”์ง€ ํƒ์ƒ‰

skip๋ฒ„ํŠผ์— ๋‹ฌ๋ ค์žˆ๋Š” onclick event handler

breakpoint ์„ค์ •

performance tab์—์„œ call stack์„ ํ•จ๊ป˜ ๋ณด๋ฉฐ ๋ถ„์„

base.js ๋ฅผ prettifyํ•  ๊ฒฝ์šฐ 9๋งŒ์ค„์— ๋‹ฌํ•˜๋Š”๋ฐ, ์˜์‹ฌ๊ฐ€๋Š” ๋ถ€๋ถ„์„ ํ•œ์ค„ํ•œ์ค„ ๋”ฐ๋ผ๊ฐ€๋ฉฐ ๋ถ„์„ํ•ด๋ณด์•˜๋‹ค.
uglify๊ฐ€ ๋„ˆ๋ฌด ์ž˜๋ผ์žˆ๊ณ  ์ผ๋ฐ˜์ ์ธ ์›น์•ฑ๊ณผ ๋‹ฌ๋ฆฌ ์ฝœ์Šคํƒ์ด ์ž˜ ์•ˆ๋‚˜์™€์„œ ๋””๋ฒ„๊น…์ด ์‰ฝ์ง€ ์•Š์•˜๋‹ค. ์ถ”๊ฐ€์ ์œผ๋กœ youtube-dl github์— ๊ณต๊ฐœ๋œ youtube์ชฝ ์†Œ์Šค์ฝ”๋“œ๋„ ๊ฐ™์ด ๋ดค์œผ๋‚˜ ํฐ ๋„์›€์€ ๋˜์ง€ ์•Š์•˜๋‹ค. ์‹ฌํ•ด๋ฅผ ํƒ์‚ฌํ•˜๋Š” ๊ธฐ๋ถ„์ด์—ˆ๊ณ  ๋ช‡ ์‹œ๊ฐ„์ฏค ๋ณด๋‹ค๋ณด๋‹ˆ ์ •์‹ ๋‚˜๊ฐˆ๊ฑฐ๊ฐ™๋‹ค๋Š” ์ƒ๊ฐ์ด ๋“ค์–ด, ๊ทธ๋งŒ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์„ ์•Œ์•„๋ณด๊ธฐ๋กœ ํ–ˆ๋‹ค

[3] AdBlock์€ ์–ด๋–ป๊ฒŒ ํ•˜๋Š”๊ฐ€

github์— public ๊ณต๊ฐœ๋œ chrome extension๋“ค๋„ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ skip ๋ฒ„ํŠผ์„ triggerํ•˜๋Š” ๋ถˆ์™„์ „ํ•œ ๋ฐฉ์‹์ด๋ผ skip ๋ฒ„ํŠผ์ด ์—†๋Š” ๊ด‘๊ณ ์˜ ๊ฒฝ์šฐ ์†์ˆ˜๋ฌด์ฑ…์ด์—ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ AdBlock extension์€ ๋ชจ๋“  ์ข…๋ฅ˜์˜ YouTube ๊ด‘๊ณ ๋ฅผ skipํ•œ๋‹ค. ์ข€ ๋” ์ข‹์€ ๋ฐฉ๋ฒ•์„ ์“ฐ๋Š” ๋ชจ์–‘์ธ๋ฐ ์•ˆํƒ€๊น๊ฒŒ๋„ ์˜คํ”ˆ์†Œ์Šค๊ฐ€ ์•„๋‹ˆ์—ˆ๋‹ค. ์•„์‰ฌ์šด๋Œ€๋กœ adblock์˜ ์†Œ์Šค์ฝ”๋“œ๋ฅผ ๊นŒ๋ณด๊ณ ์ž https://robwu.nl/crxviewer ๋ฅผ ์ด์šฉํ•˜์—ฌ extension ํŒŒ์ผ์„ ์–ป์„์ˆ˜ ์žˆ์—ˆ๋‹ค. ๋‹คํ–‰ํžˆ uglify๊ฐ€ ์•ˆ๋ผ์žˆ๊ณ  ์นœ์ ˆํ•˜๊ฒŒ ์ฃผ์„๋„ ๋‹ฌ๋ ค์žˆ๋‹ค ๊ฐธ๊ฟ€~๐Ÿ˜‹

500์ค„ ์ •๋„์˜ ์งง์€ content script์˜€๊ณ , ์ฃผ๋กœ ๋‘ ๊ฐ€์ง€ ๊ฒฝ์šฐ์— ๋Œ€ํ•ด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ฒ˜๋ฆฌํ•œ๋‹ค
1. skip ad ๋ฒ„ํŠผ์ด ์žˆ๋Š” ๊ด‘๊ณ  -> hidden์ฒ˜๋ฆฌ๋œ ๋ฒ„ํŠผ์„ ํด๋ฆญ
2. skip ad ๋ฒ„ํŠผ์ด ์—†๋Š” ๊ด‘๊ณ  -> <video> ํƒœ๊ทธ๋ฅผ ์žก์•„ currentTime = 10000 ์ฒ˜๋ฆฌ

์ฒซ๋ฒˆ์งธ ๊ฒฝ์šฐ๋Š” ์ด๋ฏธ ์•Œ๊ณ ์žˆ๊ณ , ๊ถ๊ธˆํ–ˆ๋˜ ๋‘๋ฒˆ์งธ ๊ฒฝ์šฐ๋Š” ํ—›์›ƒ์Œ์ด ๋‚˜์˜ฌ ์ •๋„๋กœ ๊ฐ„๋‹จํ•œ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•˜๊ณ ์žˆ๋‹ค. "์ด๊ฒŒ ๋œ๋‹ค๊ณ ?" ๋ผ๋Š” ์ƒ๊ฐ์ด ๋ฐ”๋กœ ๋“ค์—ˆ์œผ๋‚˜ ์ƒˆ ํƒญ์„ ์—ด์–ด ์‹คํ—˜ํ•ด๋ณธ ๊ฒฐ๊ณผ ์ž˜ ๋™์ž‘ํ•˜์˜€๋‹ค. ์˜ค๋งŒ๊ฐ€์ง€ ์ƒ๊ฐ์ด ์Šค์ณ๊ฐ”์œผ๋‚˜ ๋’ค์— ์ ๊ธฐ๋กœ ํ•˜๊ณ  ์ผ๋‹จ ๋‚ด chrome extension์— ์ ์šฉ๋ถ€ํ„ฐ ํ•ด๋ณด๊ธฐ๋กœ ํ–ˆ๋‹ค.

[4] ๊ตฌํ˜„

์˜์ƒ ์žฌ์ƒ์— ์‚ฌ์šฉ๋˜๋Š” <video> Element๋Š” HTMLMediaElement ์˜ ๊ตฌํ˜„์ฒด๋กœ์„œ currentTime ์†์„ฑ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค. ์ด ๊ฐ’์€ ํ˜„์žฌ ๋ณด๊ณ ์žˆ๋Š” ์˜์ƒ์˜ ๋ณด๊ณ ์žˆ๋Š” ์˜์ƒ์˜ ํ˜„์žฌ ์‹œ๊ฐ„์„ ์ดˆ๋‹จ์œ„๋กœ ํ‘œํ˜„ํ•˜๋Š”๋ฐ, ์ด ๊ฐ’์„ ๋ณ€๊ฒฝํ•  ๊ฒฝ์šฐ ๋ณ€๊ฒฝ๋œ ์‹œ๊ฐ„์œผ๋กœ ์ด๋™(seek)ํ•˜๊ฒŒ ๋œ๋‹ค. ์ด ์†์„ฑ์„ ์ด์šฉํ•˜์—ฌ ๊ด‘๊ณ ๊ฐ€ ๋œฐ ๊ฒฝ์šฐ 1000์ดˆ ๋’ค๋กœ ์ด๋™์‹œ์ผœ๋ฒ„๋ฆฌ๋ฉด ๊ด‘๊ณ ๊ฐ€ ๋๋‚˜๊ฒŒ ๋œ๋‹ค. ๋น„๊ฒํ•œ ์ˆ˜๋ฒ•์ด์ง€๋งŒ ๊ณ ๋ง™๊ฒŒ๋„ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ตฌํ˜„์ด ๋งค์šฐ ๊ฐ„๋‹จํ•˜๋‹ค๋Š” ์žฅ์ ์ด ์žˆ๋‹ค.

const timeWarp = () => {
  const video = document.querySelector("html5-video-player video");
  video.currenTime = 10000;
}

ํ•™๊ต๋‚˜ ํšŒ์‚ฌ์—์„œ ์˜๋ฌด์ˆ˜๊ฐ•ํ•ด์•ผํ•˜๋Š” ๊ต์œก ๋™์˜์ƒ๋„ ์ด๋Ÿฐ ๋ฐฉ๋ฒ•์œผ๋กœ ๊ฐ•์ œ skip์ด ๊ฐ€๋Šฅํ•œ ๊ฒฝ์šฐ๊ฐ€ ๋งŽ๋‹ค. ๊ธฐ์กด ์ฝ”๋“œ์— ์œ„์˜ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ด‘๊ณ ๊ฐ€ 2์—ฐํƒ€๋กœ ๋œจ๋”๋ผ๋„ ๊ด‘๊ณ ๋ฅผ ์ž˜ ๋„˜๊ธธ์ˆ˜ ์žˆ๋‹ค.

ํ•˜์ง€๋งŒ ์ž˜ ๋ณด๋ฉด ๊ด‘๊ณ ๊ฐ€ ์—ฐ์†์œผ๋กœ ๋œจ๋Š” ๊ฒฝ์šฐ์—๋Š” 1์ดˆ์ •๋„ ๊ด‘๊ณ ๋ฅผ ๋ณด๊ฒŒ๋œ๋‹ค. setInterval์„ 1์ดˆ๋งˆ๋‹ค ๊ฑธ์–ด๋†“์€ ํƒ“์ธ๋ฐ, ๊ทธ๋ ‡๋‹ค๊ณ  interval๊ฐ’์„ 1์ดˆ๋ณด๋‹ค ์ค„์ด๋ฉด ๋ธŒ๋ผ์šฐ์ €์— ๋ถ€ํ•˜๊ฐ€ ๋Š˜์–ด๋‚˜๊ฒŒ ๋œ๋‹ค. ์•„์˜ˆ polling ๋ฐฉ์‹์„ ๋ฒ„๋ฆฌ๊ณ  ์ข€๋” ๊ณ ๊ธ‰์Šค๋Ÿฌ์šด ๋ฐฉ๋ฒ•์„ ์จ๋ณด๊ธฐ๋กœ ํ•œ๋‹ค.

[5] ์ถ”๊ฐ€ ๊ฐœ์„ 

์ง€๋‚œ๋ฒˆ ํฌ์ŠคํŠธ์—์„œ mutationObserver๋ฅผ ์ž ๊น ์–ธ๊ธ‰ํ•˜์˜€๋Š”๋ฐ, DOM์˜ ๋ณ€ํ™”๋ฅผ ๊ฐ์ง€ํ• ์ˆ˜ ์žˆ๋Š” API์ด๋‹ค. ๊ด‘๊ณ ๊ฐ€ ๋– ์žˆ์„ ๋•Œ๋Š” DOM ์–ด๋”˜๊ฐ€ ํ‘œ์‹œ๊ฐ€ ๋‚  ๊ฒƒ์ด๊ณ  ์ด๋ฅผ ๊ฐ์ง€ํ•˜์—ฌ ๊ด‘๊ณ ๋ฅผ skipํ•˜๋„๋ก ํ•˜๋ฉด ๋ธŒ๋ผ์šฐ์ €์— ๋ถ€ํ•˜๋ฅผ ์ ๊ฒŒ ์ค„์ˆ˜ ์žˆ์„๊ฒƒ์ด๋‹ค.
<video> ๋ฅผ ๊ฐ์‹ธ๊ณ ์žˆ๋Š” div.html5-video-player๋ฅผ ๋ณด๋‹ˆ ๊ด‘๊ณ ๊ฐ€ ๋– ์žˆ์„ ๋•Œ "ad-showing"์ด๋ผ๋Š” class๊ฐ€ ์กด์žฌํ•˜์—ฌ ์ด๋ฅผ ๊ฐ์ง€ํ•˜์—ฌ ๊ด‘๊ณ ๋ฅผ skipํ•˜๋„๋ก ๊ตฌํ˜„ํ•ด๋ณธ๋‹ค. trigger()๋Š” ์ง€๋‚œ ํฌ์ŠคํŒ…์—์„œ ๊ตฌํ˜„ํ•œ ๊ฐ•์ œ ๋ฒ„ํŠผ ํด๋ฆญ ํ•จ์ˆ˜, timeWarp()๋Š” ์ด๋ฒˆ์— ๊ตฌํ˜„ํ•œ ํ•จ์ˆ˜.

const checkAdsPlaying = (mutationsList) => {
  for (const mutation of mutationsList) {
    if (mutation.target.classList.contains("ad-showing")) {
      const videoWrapper = mutation.target;
      trigger(videoWrapper) || timeWarp(videoWrapper)
    }
  }
};
const observer = new MutationObserver(checkAdsPlaying);
observer.observe(target, { attributes: true, attributeFilter: ["class"] });

๋ฌผ๋ก  ์ด๊ฒƒ ๋งŒ์œผ๋กœ ์ž˜ ๋™์ž‘ํ•˜์ง€๋Š” ์•Š๋Š”๋ฐ

  • ์•ฑ์ด ๋กœ๋“œ๋˜๊ณ <video> element๊ฐ€ DOM์— ๋ถ™์€ ์ดํ›„์— ์œ„์˜ ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋˜์–ด์•ผ ํ•จ
  • ๊ด‘๊ณ ๊ฐ€ ๋– ์žˆ๋Š”์ง€๋ฅผ ํŒ๋‹จํ•˜๋Š” ๋กœ์ง์ด ์™„์ „ํ•˜์ง€ ์•Š์•„ ํ•œ ๊ด‘๊ณ ์— timeWarp๊ฐ€ 7ํšŒ์ •๋„ ํ˜ธ์ถœ
  • currentTime ๊ฐ’์„ ๋ฐ”๊พธ๊ณ ๋‚˜์„œ '์ฆ‰์‹œ' ๊ด‘๊ณ ๊ฐ€ ๋„˜์–ด๊ฐ€์ง€๋Š” ์•Š๋Š”๊ฒƒ ๊ฐ™์Œ

์œ„์˜ ์ด์Šˆ๋ฅผ ๋Œ€์ถฉ ํ•ด๊ฒฐํ•˜๊ณ  ์ตœ์ข… ๊ตฌํ˜„๋œ ์ „์ฒด ์ฝ”๋“œ๋Š” ์—ฌ๊ธฐ๋ฅผ ์ฐธ์กฐ ๋ฐ”๋ž€๋‹ค.
interval ์—†์ด ๊ด‘๊ณ ๊ฐ€ ๋œจ๋ฉด ๋ฐ”๋กœ skip ํ•˜๋ฏ€๋กœ, ๊ด‘๊ณ ๊ฐ€ 2์—ฐํƒ€๋กœ ๋“ฑ์žฅํ•˜๋Š” ๊ฒฝ์šฐ์—๋„ ์ข€๋” ์Šค๋ฌด์Šค~ํ•˜๊ฒŒ ๊ด‘๊ณ  skip์ด ๋œ๋‹ค!

[6] ์ƒ๊ฐํ•ด ๋ณผ ๊ฑฐ๋ฆฌ

result

  • 5์ดˆํ›„ skip ๋ฒ„ํŠผ์ด ๋œจ๋Š” ๊ด‘๊ณ  โœ…
  • ๋ฌด์กฐ๊ฑด ๋ณผ์ˆ˜๋ฐ–์— ์—†๋Š” 5์ดˆ์งœ๋ฆฌ ๊ด‘๊ณ  โœ…
  • ๋™์˜์ƒ ์‹œ์ฒญ ์ค‘์— ํ•˜๋‹จ์— ๋œจ๋Š” ํŒ์—… โœ…
  • 10๋ถ„ ๊ฐ„๊ฒฉ์œผ๋กœ ๋œจ๋Š” ๊ด‘๊ณ (๊ธด ์˜์ƒ) โœ…
  • iframe ์— embeded๋œ youtube page โ˜‘๏ธ

์ด์ œ ์›ฌ๋งŒํ•œ ๊ฒฝ์šฐ์— ๋Œ€ํ•ด์„œ๋Š” ๊ด‘๊ณ ์ฐจ๋‹จ์ด ์ž˜ ๋œ๋‹ค. ๋งˆ์ง€๋ง‰ ์ผ€์ด์Šค๋Š” "youtube.com" ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ๋ชจ๋“  ๋ฐฉ๋ฌธํ•˜๋Š” ์‚ฌ์ดํŠธ์— ๋Œ€ํ•ด chrome-extension์„ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ถŒํ•œ์„ค์ •์„ ํ•ด์•ผ ํ•˜๋Š”๋ฐ ๊ทธ๊ฒƒ๊นŒ์ง€๋Š” ๋ฐ”๋ผ์ง€ ์•Š์œผ๋ฏ€๋กœ ํ•˜์ง€ ์•Š๊ธฐ๋กœ ํ•จ.

๊ด‘๊ณ  ์žฌํ˜„ ๊ฟ€ํŒ

ํฌ๋กฌ ์‹œํฌ๋ฆฟ๋ชจ๋“œ๋กœ ์ƒˆ ํƒญ์„ ์—ด๊ณ , ์œ ํˆฌ๋ธŒ๋ฅผ ์ผœ์„œ melon top 100์ด๋‚˜ ๋”ฉ๊ณ  ํ”„๋ฆฌ์Šคํƒ€์ผ๊ณผ ๊ฐ™์ด ์ €์ž‘๊ถŒ์ด ๊ฑธ๋ ค์žˆ๋Š” ์˜์ƒ์„ ์‹œ์ฒญํ•˜๋ฉด ๋†’์€ ํ™•๋ฅ ๋กœ ๊ด‘๊ณ ๊ฐ€ ๋œฌ๋‹ค

profile
It's just a shot away

0๊ฐœ์˜ ๋Œ“๊ธ€