הורדת סרטונים מיוטיוב לקובץ MP4 — הכול בתוך הדפדפן. בלי תוכנה, בלי שרת, בלי ffmpeg. כפתור צף בצד המסך, בחירה בין וידאו לאודיו, וזהו.
יוצא בשתי צורות מאותו קוד. שני הקישורים תמיד מצביעים על הגרסה האחרונה:
טמפרמונקי מזהה .user.js ופותח מסך התקנה. הסקריפט מוגדר עם @updateURL,
אז עדכונים מגיעים מעצמם.
לחלץ, ואז chrome://extensions ← מצב מפתחים ← "טעינת תוסף לא ארוז"
← לבחור את התיקייה שחולצה.
יוטיוב מגיש וידאו ואודיו כשני קובצי fMP4 נפרדים (DASH). אף אחד מהם אינו קובץ שאפשר לנגן לבד, ולכן צריך למזג — אבל בלי לקודד מחדש:
- קישורים — בקשה ל-
/youtubei/v1/playerבזהות לקוח visionOS. הלקוח הזה מקבל קישורים ישירים: בליsignatureCipher, בלי חניקת פרמטרnובלי PO token. זו הנקודה היחידה שיוטיוב עשוי לשבור — אז קודם בודקים מהyt-dlpמשתמש בו היום (INNERTUBE_CLIENTS). - הורדה — בקשות
&range=מקבילות (4 נתיבים, 10MB לחלק), עם ניסיונות חוזרים. 403 = הקישור פג, ואז מבקשים קישורים טריים. - מיזוג —
src/mux.js: קורא את כל ה-trunשל שני הקבצים ובונה מהםmoovאחד עם טבלאות דגימות אמיתיות (stts/ctts/stss/stsc/stsz/stco) ו-mdatאחד. הפלט אינו מפוצל — לא כי זה יפה יותר, אלא כי נגנים ותיקים ותוכנות עריכה לא פותחים קובץ מפוצל. ניתוח בייטים בלבד — לא נוגע בפריימים, ולכן זה מיידי ובלי אובדן איכות. - שמירה —
Blob+<a download>.
התפריט מציע שלוש אפשרויות:
| מה קורה | זמן | איכות | |
|---|---|---|---|
| וידאו | מיזוג וידאו+אודיו ל-MP4 | מיידי | מקור |
| אודיו · M4A | ה-AAC של יוטיוב כמו שהוא | מיידי | מקור |
| אודיו · MP3 | פענוח ב-WebAudio, קידוד ב-lamejs | שניות | 192kbps, יש אובדן |
יוטיוב לא מגיש MP3 בכלל, רק AAC — ולכן MP3 מחייב קידוד מחדש. זה השלב היחיד בפרויקט שיש בו אובדן איכות, והיחיד שלוקח זמן. ה-MP3 מקבל תגיות ID3 (שם ואמן); ה-M4A יוצא בלי תגיות.
רק פורמטי video/mp4 נבחרים, ובכל איכות מועדף avc1 (H.264) — כך שהקובץ
נפתח בכל נגן. בפועל זה תקרה של 1080p; מעל זה יוטיוב מגיש רק VP9/AV1.
בקשות וידאו גדולות נחתכות באמצע, באקראי — לא מעל סף קבוע. באותה מדידה 8MB נכשל בניסיון אחד והצליח בשניים הבאים, והזמנים קפצו בין 3.8 ל-12 שניות.
לכן החלקים הם 4MB, וחשוב מזה: מונה הניסיונות מתאפס בכל פעם שהבקשה הביאה
בייטים חדשים. חיתוך שהתקדם אינו "תקלה" אלא נקודת המשך, ורק כישלונות
רצופים ללא התקדמות סופרים לוויתור. test/fetch.test.js מאמת את זה
בחיתוך מכוון של 40% ו-70% מהבקשות.
- זיכרון — הקובץ נבנה כולו ב-RAM. אם האיכות הגבוהה לא נכנסת, הקוד יורד מדרגה אוטומטית ומודיע. סרטונים ארוכים מאוד עדיין עלולים להיכשל.
- 1080p תקרה — בכוונה, בשביל תאימות. ראה למעלה.
- חייב לרוץ בהקשר הדף (
@grant none/world: MAIN) — בלי זה אין גישה ל-ytcfgולא ל-fetch מאותו origin.
python build.py # src/ -> extension/ + userscript/ + dist/
node test/mux.test.js # מיזוג מקצה לקצה, מאומת ב-ffprobe
node test/fetch.test.js # התאוששות מחיתוכי רשת
python test/serve.py # דף דמה: http://127.0.0.1:8099/test/index.html
test/index.html מחליף את /youtubei/v1/player בפיקסצ'רים מקומיים
(נוצרו ב-ffmpeg מ-testsrc וגל סינוס) ושולח את הקובץ המוזג בחזרה לשרת,
כדי ש-ffprobe יבדוק מה שהדפדפן באמת ייצר. כך אפשר לבדוק את כל הזרימה
בלי גישה ליוטיוב.
src/util.js עזרים (h, videoId, safeName, mb)
vendor/ lame.min.js — מקודד ה-MP3
src/mux.js מיזוג fMP4 -> MP4
src/yt.js קישורים מיוטיוב, הורדה בחלקים, שמירה
src/mp3.js פענוח AAC וקידוד MP3 + תגיות ID3
src/ui.js כפתור צף, תפריט, טוסט
src/main.js חיווט, ניווט SPA
הקידוד ל-MP3 נעשה ב-LAME דרך
lamejs, ברישיון LGPL-3.0.
הספרייה נשמרת כקובץ נפרד ב-vendor/lame.min.js (עם vendor/LAME-LICENSE.txt)
ו-build.py מחבר אותה לחבילה — כך שאפשר להחליף אותה בגרסה אחרת ולבנות מחדש.