YouTube Downloader v Delphi/PHP
Aktuální verze Youtube Downloaderu se nachází na stránce YTD. Stránka, na které se nacházíte nyní, už je jen historický relikt a nemá žádnou relevanci k současnosti.
Vzhledem ke své lehce paranoidní povaze potřebuji čas od času stahovat videa z YouTube (v browseru si je nespustím, protože něco takového, jako je Flash, mi nesmí do počítače). Chvíle práce s Googlem ukáže, že program nebo webovou stránku pro stahování YouTube videa do počítače dnes napsal každý druhý uživatel internetu. Bohužel jsem za celou dobu nenašel jediný produkt, který by mi plně vyhovoval. Tak jsem si napsal vlastní, dokonce ve dvou variantách – jako samostatnou Windowsovskou aplikaci a jako PHP skript.
Při pohledu na to, kolik programů a webových stránek má se stahováním videa z YouTube potíže, by se zdálo, že napsat si vlastní stahovač je obrovská práce – už proto, že v zájmu YouTube (resp. dnes už Google) určitě není stahování nějak podporovat. Proto mě velmi překvapilo, že pokud si vystačíte s tím základním (stáhnout jedno video ze zadané stránky a uložit ho v .flv
formátu), jde o triviální operaci doslova a do písmene na pár řádek. Ďábel je pravděpodobně skryt v detailech, které jsem ovšem vyřešil pštrosím algoritmem…
Co tedy musíte udělat, pokud si chcete napsat vlastní aplikaci pro stahování videa z YouTube?
-
Získat od uživatele URL s videem (obvykle ve tvaru
http://www.youtube.com/watch?v=id_videa
) -
Tuto stránku stáhnout k sobě. Je to proto, že obsahuje některé komponenty, které jsou pro stažení videa klíčové a zřejmě je není možné získat jinak.
-
Ze stáhnuté stránky vytáhnout název videa. Nejjednodušší je použít to, co je obsahem tagu
<title>
, např. vhodným regulárním výrazem (jistě, HTML není regulární jazyk a tudíž nejde regulárním výrazem spolehlivě zpracovat, ale v souladu s pštrosím algoritmem jsou regulární výrazy i pro tento účel použitelné). V PHP by to vypadalo například takhle:$stranka = '...'; // stranka videa stahnuta z YouTube if (preg_match('~<title>(YouTube - )?(.*?)</title>~is', $stranka, $re)) { $nazev = $re[2]; } else { $nazev = '...'; // pro pripad selhani }
-
Dále je z dotyčné stránky potřeba vytáhnout speciální časovou značku, kterou YouTube používá k zabránění ve stahování videí. Lze očekávat, že tohle se bude na YouTube relativně často měnit, v současné době je to však docela jednoduché: někde v kódu stránky se deklaruje a definuje javascriptová proměnná
swfArgs
, která představuje asociativní pole, na jehož indexu „t“ je ta požadovaná časová značka. Jediný problém je, jak to „t“ rozumně dostat – ve stránce definiceswfArgs
vypadá zhruba takhle:var swfArgs = {"rv.2.thumbnailUrl": "http%3A%2F%2Fi1.ytimg.com%2Fvi%2F4L1Am0nKTdA%2Fdefault.jpg", "rv.7.length_seconds": "142", "rv.0.url": "http%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3D8EJqD61kYUY", "rv.0.view_count": "7115", "rv.2.title": "Alex+Meraz+Says+Robert+Pattinson+Smells+Like+Roses+-+Entertainment+Online", "rv.7.thumbnailUrl": "http%3A%2F%2Fi2.ytimg.com%2Fvi%2FIsXKO5eMJlM%2Fdefault.jpg", "rv.4.rating": "4.77272727273", "length_seconds": "15", ... };
Hodně stahovačů to dělá regulárním výrazem, což často uspokojivě funguje, o něco spolehlivější je ale využít toho, že
swfArgs
je definován pomocí JSON, pro který mají konvenční jazyky příslušné knihovny. Stačí tedy nějak vytáhnout celou deklaraci a předhodit ji JSON knihovně, která už si to asociativní pole vytvoří sama. Otázkou je, jak vytáhnout tu deklaraci – momentálně to dělám jiným regulárním výrazem, výhledově bude vhodné napsat si vlastní parser schopný zpracovat aspoň zásobníkovou gramatiku.if (preg_match('~\\sswfArgs\\s*=\\s*(\\{.*?\\})~is', $stranka, $re)) { $swfArgs = json_decode($re[1], TRUE); $casova_znacka = $swfArgs['t']; $id_videa = $swfArgs['video_id']; }
Všimněte si, že z swfArgs mohu rovnou vytáhnout i ID videa, nepotřebuji vůbec řešit nějaké parsování vstupního URL z bodu 1.
-
Tím už je všechno připraveno a můžeme stahovat vlastní video. Jeho URL je
http://www.youtube.com/get_video.php?video_id=ID_videa&t=Casova_znacka
, pro stáhnutí nejsou ani potřeba žádné cookies nebo autentizace. Jediný potenciální problém je v tom, že na tomto URL není přímo video, ale dochází na něm napřed k přesměrování na cílový server, na kterém teprve je video uloženo. S tím je třeba počítat, podle toho, jak konkrétně funguje stahování stránek ve vašem programovacím jazyku – pokud například v PHP použijetefopen()
afpassthru()
, tak se o přesměrování postará už PHP samotné, pokud ovšem půjdete na celou věc přes sockety (fsockopen()
a další), musíte si přesměrování vyřešit sami. Všechno jen uložíte do souboru pojmenovaného nějak jakotitulek.flv
.
Nabízím zde ke stažení dvě různé implementace.
YouTube Downloader v PHP
Tohle je asi ideální pro případ, že se chcete podívat, jak kompletní stáhnutí videa funguje: celý stahovač je tvořen jediným skriptem, který má 70 řádků a necelé 2 KB. Použití je triviální: skript nahrajete někam na svůj server a YouTubovské video pak stáhnete na adrese http://www.mujserver.cz/youtube.php?youtube_URL
, tj. například http://www.pepak.net/youtube.php?http://www.youtube.com/watch?v=8BH1HHGTCTs
(nebude fungovat, protože ten skript na mém hostingu neexistuje, ale máte to jako příklad, jak by reálné URL vypadalo). Jenom je dobré se postarat o to, aby k danému skriptu nemohl přistupovat každý – z principu věci musíte v PHP volit ze dvou špatných variant: jestli oželet název videa a stahovat přímo z YouTube, nebo jestli nabídnout stahujícímu uživateli správný název videa, ale všechno napřed stáhnout na svůj server a teprve pak to poslat uživateli. Já jsem zvolil druhou variantu, ovšem protože můj hosting mi omezuje měsíční přenosy, musím se nějak chránit proti tomu, aby přese mě někdo stahoval gigabajty a gigabajty videí… (nehledě na to, že YouTube by takové monstrózní přenosy stadno odhalil a promptně by mě odstříhl).
YouTube Downloader PHP v0.06 (26.1.2010, 1 KB). Nový formát URL na vstupu.
YouTube Downloader PHP v0.05 (25.1.2010, 1 KB). Nový formát URL na vstupu.
YouTube Downloader PHP v0.04 (19.11.2009, 1 KB). Drobná oprava – v timestampu mohly být i URL-encodované znaky (např. trailer Avatar).
YouTube Downloader PHP v0.03 (11.11.2009, 1 KB). Youtube opět změnilo strukturu svých stránek, takže se musel aktualizovat i Downloader.
YouTube Downloader PHP v0.02 (30.8.2009, 1 KB). Přináší podporu pro HD videa (přednostně se stahuje HD verze, pokud je k dispozici).
YouTube Downloader PHP v0.01 (26.8.2009, 1 KB)
YouTube Downloader v Delphi
Download v PHP jsem napsal první, později jsem ho upravil pro prostředí Delphi – důvodem bylo hlavně to, že chci mít snadnou možnost hromadně stahovat z příkazové řádky. V zásadě jde o stejný kód jako v PHP verzi výše, jen je doplněno čtení parametrů z příkazové řádky a všechno je přepsáno na vhodné Delphovské knihovny (pro regulární výrazy jsem už tradičně použil výborný TRegExpr, pro JSON lkJSON a pro vlastní stahování knihovnu Synapse českého programátora Gebyho; tu jsem jen mírně upravil, aby dovolila stahování přímo do souboru a ne napřed do paměti a teprve potom do souboru).
YouTube Downloader Delphi v0.06 (26.1.2010, 447 KB). Nový formát URL na vstupu.
YouTube Downloader Delphi v0.05 (25.1.2010, 447 KB). Nový formát URL na vstupu.
YouTube Downloader Delphi v0.04 (19.11.2009, 440 KB). Drobná oprava – v timestampu mohly být i URL-encodované znaky (např. trailer Avatar).
YouTube Downloader Delphi v0.03 (11.11.2009, 577 KB). Youtube opět změnilo strukturu svých stránek, takže se musel aktualizovat i Downloader.
YouTube Downloader Delphi v0.02 (30.8.2009, 882 KB). Přináší podporu pro HD videa (přednostně se stahuje HD verze, pokud je k dispozici).
YouTube Downloader Delphi v0.01 (26.8.2009, 884 KB – to dělají ty knihovny…)
K dořešení
Abych řekl pravdu, původně jsem se zabýval myšlenkou napsat Delphovskou verzi jen jako vhodný filtr pro stahovací utilitu WGET z projektu GNU, kterou používám pro skoro všechny své stahovací potřeby, ale nepodařilo se mi pro ni najít řešení dvou problémů. Pokud někdo ví, jak tyto problémy vyřešit, velmi bych uvítal, kdyby mi to napsal do komentářů nebo do fóra.
-
Jak vlastně zvenku předat parametry WGETu přes jeho standardní vstup? Nechci volat WGET přímo z mé utility, už proto, že bych pak musel psát rozhraní pro nastavení parametrů, ale preferoval bych „unixový“ zápis ve tvaru
wget "video_url" | downloader | wget
, resp. možná spíšwget --execute `wget "video_url | downloader`
, ale nepodařilo se mi dohledat, jak to udělat. -
Jak WGET donutit, aby pro stahovaný dokument použil mnou zadané jméno souboru? Zdálo by se, že přesně to řeší parametr
--output-file
, ale není to pravda – ten slouží k přesměrování záznamu operací do zadaného souboru, ne k pojmenování stahovaného dokumentu.
Otevřenou otázkou také zůstává, jak moc spolehlivé tohle stahování bude. Už dopředu očekávám potíže s HD videi, bohužel žádné takové neznám, abych ho mohl vyzkoušet. Také je možné, že jsem něco důležitého opomenul – zase tak moc z YouTube nestahuji, abych měl kdovíjak velký vzorek na vyzkoušení. Co jsem zkoušel, to fungovalo, ale klidně můžete narazit na video, které fungovat nebude. Když pošlete link, třeba se na to podívám 🙂
Oscar: Podle mě to v PHP nedokážeš, protože neseženeš potřebné knihovny. Doporučil bych zařídit si v ČR nějakou VPN, pak budeš mít českou IP adresu.
Myslim, e budu muset rozjet starsi verze PHP downloaderu a upravit ji, pac se nachazim mimo uzemi CR a vtakovem rpipad emi downloader na ceske weby hlasi jen hcybu 🙁 ale kdybych to snad hostoval v CR, tak by to nejak fachalo … co myslite ? je tam sance, nebo jina mzonost downloadu ? Ceskou proxynu najdu jen tezko … 🙁
Tak si stáhni zdroják aktuální verze v Delphi a převeď to. Když k máš k dispozici původní verzi v obou jazycích i dnes funkční verzi v jednom z nich, neměl by ten převod být nijak složitý.
To je škoda, o verzi PHP bych měl zájem. Tak nic.
Vzhledem k tomu, že tyhle verze jsou půl roku staré… Aktuální verze (v Delphi, PHP verze už aktualizována nebude).
Zdravím, PHP verze je zřejmě nefunkční, vypadá to, že si script nedovede poradit s dekódováním stránky. Našel by se čas na update? Diky 🙂
Ještě jeden nový formát URL.
Nový formát URL na vstupu.
Drobná aktualizace – nevěděl jsem, že timestamp může být url-encoded. To řeší např. nemožnost stáhnout trailer k Avataru.
Downloader aktualizován na verzi 0.03, která si poradí s dnešní podobou Youtube.
Kdo ví. Mě přišlo jednodušší si napsat vlastní stahovač než hledat, který z netových zrovna funguje…
(Když už mluvíme o zex.cz, tak jsem dal právě stáhnout jedno video a:
1) Nabídne mi to MP4, přestože dané video v této verzi na YouTube neexistuje
2) Nenabídne mi to název videa z YouTube ale generický název)
Není jednodušší napsat do prohlížeče rovnou http://zex.cz ? Přes ty stránky jsem vždycky stáhl co jsem potřeboval, navíc je možné si tam vybrat jestli stahovat .flv, .mp4 nebo i .gp3 pro mobily. Zároveň ten downloader podporuje i asi deset dalších videoserverů, jako například stream.cz, zkouknito.cz, čeknito.cz atd.
Verze 0.02 přináší podporu pro HD video (ve formátu .mp4) – pokud je k dispozici HD verze, stahuje se ta.