Subversion Repositories yt_downloader

Rev

Rev 13 | Rev 16 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 daniel-mar 1
<?php
2
 
14 daniel-mar 3
// ViaThinkSoft YouTube Downloader Functions 2.3
13 daniel-mar 4
// Revision: 2022-02-06
2 daniel-mar 5
// Author: Daniel Marschall <www.daniel-marschall.de>
7 daniel-mar 6
// Licensed under the terms of the Apache 2.0 License
2 daniel-mar 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;
48
 
49
                $obj = json_decode($cont, true);
50
                if (!$obj) return false;
51
 
8 daniel-mar 52
                if (!isset($obj['items'])) return false;
53
 
2 daniel-mar 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
 
8 daniel-mar 76
        if (!isset($obj['items'])) return false;
77
 
2 daniel-mar 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
 
8 daniel-mar 92
        if (!isset($obj['items'])) return false;
93
 
2 daniel-mar 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
 
8 daniel-mar 108
        if (!isset($obj['items'])) return false; //totalResults could be 0
109
 
2 daniel-mar 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
 
8 daniel-mar 124
        if (!isset($obj['items'])) return false;
125
 
2 daniel-mar 126
        foreach ($obj['items'] as $item) {
127
                if ($item['kind'] == 'youtube#playlist') {
128
                        return $item['contentDetails'];
129
                }
130
        }
131
}
132
 
133
function yt_channel_items($channel_id, $searchterms='', $maxresults=-1) {
134
        $out = array();
135
 
136
        $next_page_token = '';
137
 
138
        do {
139
                $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()));
140
                if (!$cont) return false;
141
 
142
                $obj = json_decode($cont, true);
143
                if (!$obj) return false;
144
 
8 daniel-mar 145
                if (!isset($obj['items'])) return false;
146
 
2 daniel-mar 147
                foreach ($obj['items'] as $item) {
148
                        if ($item['id']['kind'] == 'youtube#video') {
149
                                $title    = $item['snippet']['title'];
150
                                $video_id = $item['id']['videoId'];
151
                                $out[] = array($video_id, $title);
152
                                if (($maxresults != -1) && ($maxresults == count($out))) return $out;
153
                        }
154
                }
155
 
156
                $next_page_token = isset($obj['nextPageToken']) ? $obj['nextPageToken'] : '';
157
        } while ($next_page_token != '');
158
 
159
        return $out;
160
}
161
 
162
// Acceptable order values are: date, rating, relevance(default), title, videoCount, viewCount
163
function yt_search_items($searchterms, $order='', $maxresults=-1) {
164
        $out = array();
165
 
166
        $next_page_token = '';
167
 
168
        do {
169
                $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()));
170
                if (!$cont) return false;
171
 
172
                $obj = json_decode($cont, true);
173
                if (!$obj) return false;
174
 
8 daniel-mar 175
                if (!isset($obj['items'])) return false;
176
 
2 daniel-mar 177
                foreach ($obj['items'] as $item) {
178
                        if ($item['id']['kind'] == 'youtube#video') {
179
                                $title    = $item['snippet']['title'];
180
                                $video_id = $item['id']['videoId'];
181
                                $out[] = array($video_id, $title);
182
                                if (($maxresults != -1) && ($maxresults == count($out))) return $out;
183
                        }
184
                }
185
 
186
                $next_page_token = isset($obj['nextPageToken']) ? $obj['nextPageToken'] : '';
187
        } while ($next_page_token != '');
188
 
189
        return $out;
190
}
191
 
192
function getVideoIDFromURL($url) {
193
        // Extract video ID from the URL
194
 
195
        $vid = false;
7 daniel-mar 196
        $m = null;
2 daniel-mar 197
 
198
        # Usual format
8 daniel-mar 199
        if (($vid === false) && (preg_match("@https{0,1}://(www\\.|)youtube\\.com/watch(.*)(/|&|\\?)v=([a-zA-Z0-9_-]{11})@ismU", $url, $m))) {
2 daniel-mar 200
                $vid = $m[4];
201
        }
202
 
203
        # Short format
12 daniel-mar 204
        if (($vid === false) && (preg_match("@https{0,1}://(www\\.|)youtu\\.be/([a-zA-Z0-9_-]{11})@ismU", $url, $m))) {
2 daniel-mar 205
                $vid = $m[2];
206
        }
207
 
7 daniel-mar 208
        # YouTube "Shorts"
209
        if (($vid === false) && (preg_match("@https{0,1}://(www\\.|)youtube\\.com/shorts/([a-zA-Z0-9_-]{11})@ismU", $url, $m))) {
210
                $vid = $m[2];
211
        }
212
 
2 daniel-mar 213
        return $vid;
214
}
215
 
216
function getPlaylistIDFromURL($url) {
217
        $pid = false;
218
 
219
        # Usual format
7 daniel-mar 220
        $m = null;
8 daniel-mar 221
        if (($pid === false) && (preg_match("@https{0,1}://(www\\.|)youtube\\.com/(.*)(/|&|\\?)list=(.+)&@ismU", $url.'&', $m))) {
2 daniel-mar 222
                $pid = $m[4];
223
        }
224
 
225
        return $pid;
226
}
227
 
228
function yt_check_apikey_syntax($apikey) {
229
        return preg_match('@^[a-zA-Z0-9]{39}$@', $apikey);
230
}
231
 
232
function yt_check_video_id($video_id) {
233
        return preg_match('@^[a-zA-Z0-9\-_]{11}$@', $video_id);
234
}
235
 
13 daniel-mar 236
function yt_get_channel_id_from_custom_url($custom_url) {
237
        // TODO: is there any API possibility??? API only accepts username and id ?!
238
 
239
        // https://www.youtube.com/c/SASASMR
240
        // <link rel="canonical" href="https://www.youtube.com/channel/UCp4LfMtDfoa29kTlLnqQ5Mg">
241
        // https://www.youtube.com/impaulsive
242
        // <link rel="canonical" href="https://www.youtube.com/channel/UCGeBogGDZ9W3dsGx-mWQGJA">
243
 
244
        $cont = file_get_contents($custom_url);
245
        if ($cont === false) {
246
                throw new Exception("Cannot open $custom_url using file_get_contents.");
247
        }
248
        if (!preg_match('@<link rel="canonical" href="https://www.youtube.com/channel/([^"]+)">@ismU', $cont, $m)) {
249
                return false;
250
        }
251
 
252
        return $m[1];
253
}
254
 
255
function yt_get_channel_id_from_url($channel_url) {
256
        $m = null;
257
        if (preg_match("@https{0,1}://(www\\.|)youtube\\.com/user/(.*)(/|&|\\?)@ismU", $channel_url.'&', $m)) {
258
                // Username (deprecated feature. Not every channel has a username associated with it)
259
                // https://www.youtube.com/user/USERNAME
260
                $username = $m[2];
261
                $channel_id = yt_get_channel_id($username);
262
                return $channel_id;
263
        } else if (preg_match("@https{0,1}://(www\\.|)youtube\\.com/channel/(.*)(/|&|\\?)@ismU", $channel_url.'&', $m)) {
264
                // Real channel ID
265
                // https://www.youtube.com/channel/ID
266
                $channel_id = $m[2];
267
                return $channel_id;
268
        } else if (preg_match("@https{0,1}://(www\\.|)youtube\\.com/(c/){0,1}(.*)(/|&|\\?)@ismU", $channel_url.'&', $m)) {
269
                // Channel custom URL
270
                // https://www.youtube.com/NAME or https://www.youtube.com/c/NAME
271
                return yt_get_channel_id_from_custom_url($channel_url);
272
        } else {
273
                return false;
274
        }
275
}
276
 
2 daniel-mar 277
// Examples:
278
//yt_set_apikey(trim(file_get_contents(__DIR__ . '/.yt_api_key')));
279
//print_r(yt_playlist_items('PL9GbGAd-gY1pyxZJIX5MOdYdRbdweVAID'));
280
//print_r(yt_channel_items('UCjPjcMEAN64opOoNQE9GykA'));
281
//print_r(yt_channel_items('UCjPjcMEAN64opOoNQE9GykA', 'Knight'));
282
//print_r(yt_search_items('Wesley Willis', 'date', 10));