yt-feed-generator-v3/index.php

175 lines
5.5 KiB
PHP
Executable File

<?php
$baseurl = 'https://www.googleapis.com/youtube/v3';
$my_key = '';
$username = '';
$nb_entries = 20;
$thumb_quality = 'medium'; // can be 'default', 'medium', 'high', 'standard', 'maxres'
function get_channel_for_user($user)
{
global $baseurl, $my_key;
$url = $baseurl . '/channels?part=id&forUsername=' . $user . '&key=' . $my_key;
$response = @file_get_contents($url);
$data = json_decode($response, true);
return $data['items'][0]['id'];
}
function get_playlists($channel)
{
global $baseurl, $my_key;
$playlists = array();
// we have to get the full snippet here, because there is no other way to get the channelId
// of the channels you're subscribed to. 'id' returns a subscription id, which can only be
// used to subsequently get the full snippet, so we may as well just get the whole lot up front.
$url = $baseurl . '/subscriptions?part=snippet&channelId=' . $channel . '&maxResults=50&key=' . $my_key;
$next_page = '';
while (true) {
// we are limited to 50 results. if the user subscribed to more than 50 channels
// we have to make multiple requests here.
$response = @file_get_contents($url . $next_page);
$data = json_decode($response, true);
$subs = array();
foreach ($data['items'] as $i) {
if ($i['kind'] == 'youtube#subscription') {
$subs[] = $i['snippet']['resourceId']['channelId'];
}
}
// actually getting the channel uploads requires knowing the upload playlist ID, which means
// another request. luckily we can bulk these 50 at a time.
$purl = $baseurl . '/channels?part=contentDetails&id=' . implode('%2C', $subs) . '&maxResults=50&key=' . $my_key;
$response2 = @file_get_contents($purl);
$data2 = json_decode($response2, true);
foreach ($data2['items'] as $i2) {
if (!empty($i2['contentDetails']['relatedPlaylists']['uploads'])) {
$playlists[] = $i2['contentDetails']['relatedPlaylists']['uploads'];
}
}
if (!empty($data['nextPageToken'])) { // loop until there are no more pages
$next_page = '&pageToken=' . $data['nextPageToken'];
} else {
break;
}
}
return $playlists;
}
function get_playlist_items($playlist)
{
global $baseurl, $my_key;
$videos = array();
// get the last 5 videos uploaded to the playlist
$url = $baseurl . '/playlistItems?part=contentDetails&playlistId=' . $playlist . '&maxResults=5&key=' . $my_key;
$response = @file_get_contents($url);
$data = json_decode($response, true);
foreach ($data['items'] as $i) {
if ($i['kind'] == 'youtube#playlistItem') {
$videos[] = $i['contentDetails']['videoId'];
}
}
return $videos;
}
function get_real_videos($video_ids)
{
global $baseurl, $my_key;
$purl = $baseurl . '/videos?part=snippet&id=' . implode('%2C', $video_ids) . '&maxResults=50&key=' . $my_key;
$response = @file_get_contents($purl);
$data = json_decode($response, true);
return $data['items'];
}
// get all upload playlists of subbed channels
$playlists = get_playlists(get_channel_for_user($username));
// get the last 5 items from every playlist
$allitems = array();
foreach ($playlists as $p) {
$allitems = array_merge($allitems, get_playlist_items($p));
}
// the playlist items don't contain the correct published date, so now
// we have to fetch every video in batches of 50.
$allvids = array();
for ($i = 0; $i < count($allitems); $i = $i + 50) {
$rvids = get_real_videos(array_slice($allitems, $i, 50));
if ($rvids) {
foreach ($rvids as $r) {
$allvids[] = $r;
}
} else {
break;
}
}
// sort them by date
function cmp($a, $b)
{
$a = strtotime($a['snippet']['publishedAt']);
$b = strtotime($b['snippet']['publishedAt']);
if ($a == $b) {
return 0;
}
return ($a > $b) ? -1 : 1;
}
usort($allvids, 'cmp');
// Fix to include CDATA (from http://stackoverflow.com/a/20511976)
class SimpleXMLElementExtended extends SimpleXMLElement
{
public function addChildWithCDATA($name, $value = null, $namespace = null)
{
$new_child = $this->addChild($name, null, $namespace);
if (isset($new_child)) {
$node = dom_import_simplexml($new_child);
$no = $node->ownerDocument;
$node->appendChild($no->createCDATASection($value));
}
return $new_child;
}
}
// build the rss
$rss = new SimpleXMLElementExtended('<rss version="2.0"></rss>');
$channel = $rss->addChild('channel');
$channel->title = 'Youtube subscriptions for ' . $username;
$channel->link = 'http://www.youtube.com/';
$channel->description = 'YouTube RSS feed generator by Xefir Destiny ; ported from python ytsubs by ali1234 https://github.com/ali1234/ytsubs';
$atom = $channel->addChild('link', null, 'http://www.w3.org/2005/Atom');
$atom->addAttribute('href', 'http://' . $_SERVER['SERVER_NAME'] . dirname($_SERVER['REQUEST_URI']) . '/rss.xml');
$atom->addAttribute('rel', 'self');
// add the most recent
for ($v = 0; $v < $nb_entries; $v++) {
$link = 'http://youtube.com/watch?v=' . $allvids[$v]['id'];
$item = $channel->addChild('item');
$item->link = $link;
$item->addChildWithCDATA('title', $allvids[$v]['snippet']['title']);
$item->addChildWithCDATA('description', '
<table>
<tr>
<td><img src="' . $allvids[$v]['snippet']['thumbnails'][$thumb_quality]['url'] . '" alt="default" /></td>
<td>' . str_replace("\n", '<br>', htmlentities($allvids[$v]['snippet']['description'])) . '</td>
</tr>
</table>');
$item->guid = $link;
$item->pubDate = date(DATE_RSS, strtotime($allvids[$v]['snippet']['publishedAt']));
$item->addChildWithCDATA('dc:creator', $allvids[$v]['snippet']['channelTitle'], 'http://purl.org/dc/elements/1.1/');
}
$rss->saveXML('rss.xml');
header('Content-Type: application/rss+xml');
echo $rss->asXML();