Projektowanie stron WWW od podszewki

Artykuły na każdy temat

[PHP] Ściąganie filmów z YouTube i przerabianie ich na mp3

Dodano 01.12.2013r. o 22:48
W sieci jest wiele narzędzi, które ułatwiają ściąganie materiałów z serwisów takich jak YouTube, a następnie ich konwersja na format mp3. Chyba jednym z najpopularniejszych serwisów oferujących takiego typu usługi jest strona youtube-mp3.org. Dodatkowo dla każdej z przeglądarek są odpowiednie wtyczki umożliwiające ściąganie filmów w określonych formatach. Przykładem np. Easy Youtube Video Downloader (Firefox), YouTube Downloader (Opera), Chrome YouTube Downloader i tak dalej. Są też specjalne narzędzia, które wyłapują wszystkie flashowe pliki ze strony i pozwalają na ich zapis. Następnie pozostaje konwersja do określonego wybranego formatu lub zainstalowanie odpowiedniego kodeka. Dla serwisów wykorzystujących technologię Silverlight (przykładem rodzime VOD) są dedykowane aplikacje, które umożliwiają ściąganie materiałów na podstawie analizy pakietów.

Wszystko jest spoko do czasu, kiedy np. nie ma się do ściągnięcia więcej niż kilku plików. W przypadku ilości hurtowych takie rozwiązanie jest oczywiście niepraktyczne i posiadanie "automatu" byłoby mocno na rękę, prawda? Szczerze mówiąc nie spotkałem się jeszcze z takim, ale może dlatego, że słabo szukałem. Natrafiłem na kilka, ale nie zdały egzaminu. Po za tym korzystanie z np. zewnętrznych serwisów wiąże się z limitem na ilość zapytań na określony czas. Dlatego szybko przyszło mi do głowy, aby napisać własne narzędzie. Potrzebne informacje oczywiście znalazłem w sieci. Po przepisaniu kodu na nowo, wprowadzeniu kilku usprawnień i innych poprawek skrypt prezentuje się następująco:
Kod:
<?php
// For the purity of conscience
set_time_limit(0);
// Config
$config['user'] = 'MrSuicideSheep';
$config['path']['mp3'] = './mp3/'.$config['user'].'/';
$config['path']['wget'] = 'D:\xampp\htdocs\yt-downloader\wget.exe';
$config['path']['ffmpeg'] = 'D:\xampp\htdocs\yt-downloader\ffmpeg.exe';
// Do what you have to do
$list get_video_list($config['user']);

// Grab videos
foreach($list as $item)
{
 $video_address get_youtube_video($item[0]);
 $video_file get_temporary_file_name();
 $audio_file get_temporary_file_name();
 system($config['path']['wget'].' -O "'.$video_file.'" "'.$video_address.'"'$wget_return);

 if($wget_return == 0)
 {
  // Convert file
  system($config['path']['ffmpeg'].' -i "'.$video_file.'" -vn -f mp3 "'.$audio_file.'"'$ffmpeg_return);

  if($ffmpeg_return == 0)
  {
   // Create the file name wihout illegal symbols (Windows rule)
   $new_file_name $config['path']['mp3'].trim(preg_replace('#[\\\\/\:\*\?"<>|]#'''$item[1])).'.mp3';
   // This code is not here for fun
   rename($audio_file$new_file_name);
  }
 }

 if(file_exists($video_file))
 {
  unlink($video_file);
 }

 if(file_exists($audio_file))
 {
  unlink($audio_file);
 }
}

// Whatever
echo 'Done!';

function get_video_list($user)
{
 for($h 1$h <= $how || !$initiated$h += 50)
 {
  $list json_decode(file_get_contents('http://gdata.youtube.com/feeds/api/users/'.$user.'/uploads?v=2&alt=jsonc&max-results=50&start-index='.$h));

  if(!$initiated)
  {
   $how $list -> data -> totalItems;
   $initiated true;
  }

  foreach($list -> data -> items as $item)
  {
   $data[] = array($item -> idtrim($item -> title));
  }
 }

 return $data;
}

function get_youtube_video($video_id)
{
 while(1)
 {
  $ch curl_init('http://www.youtube.com/get_video_info?video_id='.$video_id);
  curl_setopt($chCURLOPT_RETURNTRANSFERtrue);
  $video_info curl_exec($ch);
  $headers curl_getinfo($ch);
  curl_close($ch);

  if($headers['http_code'] == 200)
  {
   break;
  }
  else
  {
   sleep(1);
  }
 }

 parse_str($video_info);

 if($url_encoded_fmt_stream_map)
 {
  $video_available_formats explode(','$url_encoded_fmt_stream_map);

  for($h 0$how count($video_available_formats); $h $how; ++$h)
  {
   parse_str($video_available_formats[$h]);
   $available_formats[$h]['itag'] = $itag;
   $available_formats[$h]['url'] = urldecode($url).'&signature='.$sig;
  }

  // Choose the best format (order by audio bitrate) -> warto rzucić okiem na kilka tabel z sieci odnośnie "YouTube media encoding options"
  $format_order = array(1413837224645102101172848512035443443100140171828318651393617);

  for($h 0$how = array(count($format_order), count($available_formats)); $h $how[0]; ++$h)
  {
   for($i 0$i $how[1]; ++$i)
   {
    if($format_order[$h] == $available_formats[$i]['itag'])
    {
     $chosen_format $i;

     break 2;
    }
   }
  }

  if(is_int($chosen_format))
  {
   return $available_formats[$chosen_format]['url'];
  }
 }

 return false;
}

function get_temporary_file_name()
{
 return './tmp/'.uniqid().'.tmp';
}
?>
Podobno kanały podlegające VEVO mają specjalną enkrypcje utrudniającą ściąganie. Nie wiem, nie sprawdzałem ale skoro inne serwisy (np. ten wymieniony powyżej) potrafią ściągać z tego typu kanałów to możliwość obejścia jej jest do wykonania. Oczywiście jeżeli chcemy wykorzystać skrypt na Linux'ie to potrzebujemy troszeczkę zmienić "zapytania" obok funkcji system(). wget.exe jak i ffmpeg.exe dostępne są w sieci więc nie będziecie mieli problemów ze znalezieniem ich. Dodatkowo skrypt wymaga dopracowania tj. konwersja nazwy plików tak aby w przypadku napotkania specyficznych znaków nie kończyła się krzakami w nazwie pliku. Tutaj na pomoc przyjdzie funkcja iconv(). Skrypt nie sprawdza czy film jest zablokowany na mocy praw autorskich w określonym kraju (warto dorobić taką funkcjonalność). Ponadto niektóre zwrócone adresy mogą nie działać. Wtedy warto spróbować z kolejnym formatem. Wobec itag'ów warto poszukać po sieci opracowań na ten temat (jak np. takie). wget został wykorzystany chociażby dlatego, że PHP nie radzi sobie ze ściąganiem plików o dużej gramaturze. Dodatkowo itag'i można dobierać także pod innymi kątami np. (extension). Nie jest przypadkiem, że powstała funkcja get_temporary_file_name(). Wynika to z prostego faktu, że tmpfile() i tempnam() nie spełniły moich oczekiwań. Na całe szczęście YouTube nie streamuje filmów w sposób mocno utrudniający pobieranie co bardzo cieszy. Właściwie streamowanie to tylko słowa, bo ze skryptu wszystko wynika Wink

Komentarze

Brak komentarzy

Dodaj komentarz

Zostaw komentarz jeżeli możesz! Nie bądź przysłowiowym botem! Nie bądź obojętny! Ciebie to nic nie kosztuje, a mi sprawi uśmiech na twarzy.
Zezwolono używać: BBCode
Zabroniono używać:
znaczników HTML

(Wymagany)

(Wymagany, niepublikowany)

(Nie wymagana)

Token:

Obrazek dla bota

(Przepisz tylko cyfry!)

(Wymagana)