Subversion Repositories yt_downloader

Rev

Rev 16 | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. <?php
  2.  
  3. // ViaThinkSoft YouTube Downloader Functions 2.3
  4. // Revision: 2022-12-19
  5. // Author: Daniel Marschall <www.daniel-marschall.de>
  6. // Licensed under the terms of the Apache 2.0 License
  7.  
  8. // Get API key:   https://console.developers.google.com/apis/credentials
  9. // Test API here: https://developers.google.com/apis-explorer/?hl=de#p/youtube/v3/youtube.playlistItems.list
  10.  
  11. $yt_apikey = null;
  12. $yt_apikey_callback = null;
  13.  
  14. function yt_set_apikey($apikey) {
  15.         global $yt_apikey;
  16.         $yt_apikey = $apikey;
  17. }
  18.  
  19. function yt_set_apikey_callback($apikey_callback) {
  20.         global $yt_apikey_callback;
  21.         $yt_apikey_callback = $apikey_callback;
  22. }
  23.  
  24. function yt_get_apikey() {
  25.         global $yt_apikey, $yt_apikey_callback;
  26.  
  27.         if (!empty($yt_apikey_callback)) {
  28.                 $apikey = call_user_func($yt_apikey_callback);
  29.                 if (!yt_check_apikey_syntax($apikey)) throw new Exception("Invalid API key '$apikey'");
  30.         } else if (!empty($yt_apikey)) {
  31.                 $apikey = $yt_apikey;
  32.                 if (!yt_check_apikey_syntax($apikey)) throw new Exception("Invalid API key '$apikey'");
  33.         } else {
  34.                 throw new Exception("This function requires a YouTube API key.\n");
  35.         }
  36.  
  37.         return $apikey;
  38. }
  39.  
  40. function yt_playlist_items($playlist_id, $maxresults=-1) {
  41.         $out = array();
  42.  
  43.         $next_page_token = '';
  44.  
  45.         do {
  46.                 $cont = @file_get_contents('https://www.googleapis.com/youtube/v3/playlistItems?part=snippet&playlistId='.urlencode($playlist_id).'&maxResults=50'.(($next_page_token!='') ? '&pageToken='.urlencode($next_page_token) : '').'&key='.urlencode(yt_get_apikey()));
  47.                 if (!$cont) return false; // e.g. if Playlist was deleted
  48.  
  49.                 $obj = json_decode($cont, true);
  50.                 if (!$obj) return false;
  51.  
  52.                 if (!isset($obj['items'])) return false;
  53.  
  54.                 foreach ($obj['items'] as $item) {
  55.                         if ($item['snippet']['resourceId']['kind'] == 'youtube#video') {
  56.                                 $title    = $item['snippet']['title'];
  57.                                 $video_id = $item['snippet']['resourceId']['videoId'];
  58.                                 $out[] = array($video_id, $title);
  59.                                 if (($maxresults != -1) && ($maxresults == count($out))) return $out;
  60.                         }
  61.                 }
  62.  
  63.                 $next_page_token = isset($obj['nextPageToken']) ? $obj['nextPageToken'] : '';
  64.         } while ($next_page_token != '');
  65.  
  66.         return $out;
  67. }
  68.  
  69. function yt_get_channel_id($username) {
  70.         $cont = @file_get_contents('https://www.googleapis.com/youtube/v3/channels?key='.urlencode(yt_get_apikey()).'&forUsername='.urlencode($username).'&part=id');
  71.         if (!$cont) return false;
  72.  
  73.         $obj = json_decode($cont, true);
  74.         if (!$obj) return false;
  75.  
  76.         if (!isset($obj['items'])) return false;
  77.  
  78.         foreach ($obj['items'] as $item) {
  79.                 if ($item['kind'] == 'youtube#channel') {
  80.                         return $item['id'];
  81.                 }
  82.         }
  83. }
  84.  
  85. function yt_get_channel_id_and_stats($username) {
  86.         $cont = @file_get_contents('https://www.googleapis.com/youtube/v3/channels?key='.urlencode(yt_get_apikey()).'&forUsername='.urlencode($username).'&part=id,statistics');
  87.         if (!$cont) return false;
  88.  
  89.         $obj = json_decode($cont, true);
  90.         if (!$obj) return false;
  91.  
  92.         if (!isset($obj['items'])) return false;
  93.  
  94.         foreach ($obj['items'] as $item) {
  95.                 if ($item['kind'] == 'youtube#channel') {
  96.                         return array($item['id'], $item['statistics']);
  97.                 }
  98.         }
  99. }
  100.  
  101. function yt_get_channel_stats($channel_id) {
  102.         $cont = @file_get_contents('https://www.googleapis.com/youtube/v3/channels?key='.urlencode(yt_get_apikey()).'&id='.urlencode($channel_id).'&part=statistics');
  103.         if (!$cont) return false;
  104.  
  105.         $obj = json_decode($cont, true);
  106.         if (!$obj) return false;
  107.  
  108.         if (!isset($obj['items'])) return false; //totalResults could be 0
  109.  
  110.         foreach ($obj['items'] as $item) {
  111.                 if ($item['kind'] == 'youtube#channel') {
  112.                         return $item['statistics'];
  113.                 }
  114.         }
  115. }
  116.  
  117. function yt_get_playlist_stats($playlist_id) {
  118.         $cont = @file_get_contents('https://www.googleapis.com/youtube/v3/playlists?part=contentDetails&id='.urlencode($playlist_id).'&key='.urlencode(yt_get_apikey()));
  119.         if (!$cont) return false;
  120.  
  121.         $obj = json_decode($cont, true);
  122.         if (!$obj) return false;
  123.  
  124.         if (!isset($obj['items'])) return false;
  125.  
  126.         foreach ($obj['items'] as $item) {
  127.                 if ($item['kind'] == 'youtube#playlist') {
  128.                         if (!isset($item['contentDetails']) || is_null($item['contentDetails'])) return false; // can happen to deleted playlists
  129.                         return $item['contentDetails'];
  130.                 }
  131.         }
  132. }
  133.  
  134. function yt_channel_items($channel_id, $searchterms='', $maxresults=-1) {
  135.         $out = array();
  136.  
  137.         $next_page_token = '';
  138.  
  139.         do {
  140.                 $cont = @file_get_contents('https://www.googleapis.com/youtube/v3/search?part=snippet&channelId='.urlencode($channel_id).(($searchterms!='') ? '&q='.urlencode($searchterms) : '').'&maxResults=50'.(($next_page_token!='') ? '&pageToken='.urlencode($next_page_token) : '').'&key='.urlencode(yt_get_apikey()));
  141.                 if (!$cont) return false;
  142.  
  143.                 $obj = json_decode($cont, true);
  144.                 if (!$obj) return false;
  145.  
  146.                 if (!isset($obj['items'])) return false;
  147.  
  148.                 foreach ($obj['items'] as $item) {
  149.                         if ($item['id']['kind'] == 'youtube#video') {
  150.                                 $title    = $item['snippet']['title'];
  151.                                 $video_id = $item['id']['videoId'];
  152.                                 $out[] = array($video_id, $title);
  153.                                 if (($maxresults != -1) && ($maxresults == count($out))) return $out;
  154.                         }
  155.                 }
  156.  
  157.                 $next_page_token = isset($obj['nextPageToken']) ? $obj['nextPageToken'] : '';
  158.         } while ($next_page_token != '');
  159.  
  160.         return $out;
  161. }
  162.  
  163. // Acceptable order values are: date, rating, relevance(default), title, videoCount, viewCount
  164. function yt_search_items($searchterms, $order='', $maxresults=-1) {
  165.         $out = array();
  166.  
  167.         $next_page_token = '';
  168.  
  169.         do {
  170.                 $cont = @file_get_contents('https://www.googleapis.com/youtube/v3/search?part=snippet&q='.urlencode($searchterms).(($order!='') ? '&order='.urlencode($order) : '').'&maxResults=50'.(($next_page_token!='') ? '&pageToken='.urlencode($next_page_token) : '').'&key='.urlencode(yt_get_apikey()));
  171.                 if (!$cont) return false;
  172.  
  173.                 $obj = json_decode($cont, true);
  174.                 if (!$obj) return false;
  175.  
  176.                 if (!isset($obj['items'])) return false;
  177.  
  178.                 foreach ($obj['items'] as $item) {
  179.                         if ($item['id']['kind'] == 'youtube#video') {
  180.                                 $title    = $item['snippet']['title'];
  181.                                 $video_id = $item['id']['videoId'];
  182.                                 $out[] = array($video_id, $title);
  183.                                 if (($maxresults != -1) && ($maxresults == count($out))) return $out;
  184.                         }
  185.                 }
  186.  
  187.                 $next_page_token = isset($obj['nextPageToken']) ? $obj['nextPageToken'] : '';
  188.         } while ($next_page_token != '');
  189.  
  190.         return $out;
  191. }
  192.  
  193. function getVideoIDFromURL($url) {
  194.         // Extract video ID from the URL
  195.  
  196.         $vid = false;
  197.         $m = null;
  198.  
  199.         # Usual format
  200.         if (($vid === false) && (preg_match("@https{0,1}://(www\\.|)youtube\\.com/watch(.*)(/|&|\\?)v=([a-zA-Z0-9_-]{11})@ismU", $url, $m))) {
  201.                 $vid = $m[4];
  202.         }
  203.  
  204.         # Short format
  205.         if (($vid === false) && (preg_match("@https{0,1}://(www\\.|)youtu\\.be/([a-zA-Z0-9_-]{11})@ismU", $url, $m))) {
  206.                 $vid = $m[2];
  207.         }
  208.  
  209.         # YouTube "Shorts"
  210.         if (($vid === false) && (preg_match("@https{0,1}://(www\\.|)youtube\\.com/shorts/([a-zA-Z0-9_-]{11})@ismU", $url, $m))) {
  211.                 $vid = $m[2];
  212.         }
  213.  
  214.         return $vid;
  215. }
  216.  
  217. function getPlaylistIDFromURL($url) {
  218.         $pid = false;
  219.  
  220.         # Usual format
  221.         $m = null;
  222.         if (($pid === false) && (preg_match("@https{0,1}://(www\\.|)youtube\\.com/(.*)(/|&|\\?)list=(.+)&@ismU", $url.'&', $m))) {
  223.                 $pid = $m[4];
  224.         }
  225.  
  226.         return $pid;
  227. }
  228.  
  229. function yt_check_apikey_syntax($apikey) {
  230.         return preg_match('@^[a-zA-Z0-9]{39}$@', $apikey);
  231. }
  232.  
  233. function yt_check_video_id($video_id) {
  234.         return preg_match('@^[a-zA-Z0-9\-_]{11}$@', $video_id);
  235. }
  236.  
  237. function yt_get_channel_id_from_custom_url($custom_url) {
  238.         // TODO: is there any API possibility??? API only accepts username and id ?!
  239.  
  240.         // https://www.youtube.com/c/SASASMR
  241.         // <link rel="canonical" href="https://www.youtube.com/channel/UCp4LfMtDfoa29kTlLnqQ5Mg">
  242.         // https://www.youtube.com/impaulsive
  243.         // <link rel="canonical" href="https://www.youtube.com/channel/UCGeBogGDZ9W3dsGx-mWQGJA">
  244.         // https://www.youtube.com/@KosmonautMusicSpecials
  245.         // <link rel="canonical" href="https://www.youtube.com/channel/UCayYOQ0DEIpcTgO9z_b-K1A">
  246.  
  247.         $cont = @file_get_contents($custom_url);
  248.         if ($cont === false) {
  249.                 throw new Exception("Cannot open $custom_url using file_get_contents.");
  250.         }
  251.         if (!preg_match('@<link rel="canonical" href="https://www.youtube.com/channel/([^"]+)">@ismU', $cont, $m)) {
  252.                 return false;
  253.         }
  254.  
  255.         return $m[1];
  256. }
  257.  
  258. function yt_get_channel_id_from_url($channel_url) {
  259.         $m = null;
  260.         if (preg_match("@https{0,1}://(www\\.|)youtube\\.com/user/(.*)(/|&|\\?)@ismU", $channel_url.'&', $m)) {
  261.                 // Username (deprecated feature. Not every channel has a username associated with it)
  262.                 // https://www.youtube.com/user/USERNAME
  263.                 $username = $m[2];
  264.                 $channel_id = yt_get_channel_id($username);
  265.                 return $channel_id;
  266.         } else if (preg_match("@https{0,1}://(www\\.|)youtube\\.com/channel/(.*)(/|&|\\?)@ismU", $channel_url.'&', $m)) {
  267.                 // Real channel ID
  268.                 // https://www.youtube.com/channel/ID
  269.                 $channel_id = $m[2];
  270.                 return $channel_id;
  271.         } else if (preg_match("@https{0,1}://(www\\.|)youtube\\.com/(c/){0,1}(.*)(/|&|\\?)@ismU", $channel_url.'&', $m)) {
  272.                 // Channel custom URL
  273.                 // https://www.youtube.com/NAME or https://www.youtube.com/c/NAME
  274.                 return yt_get_channel_id_from_custom_url($channel_url);
  275.         } else {
  276.                 return false;
  277.         }
  278. }
  279.  
  280. // Examples:
  281. //yt_set_apikey(trim(file_get_contents(__DIR__ . '/.yt_api_key')));
  282. //print_r(yt_playlist_items('PL9GbGAd-gY1pyxZJIX5MOdYdRbdweVAID'));
  283. //print_r(yt_channel_items('UCjPjcMEAN64opOoNQE9GykA'));
  284. //print_r(yt_channel_items('UCjPjcMEAN64opOoNQE9GykA', 'Knight'));
  285. //print_r(yt_search_items('Wesley Willis', 'date', 10));
  286.