2013-08-15 12:05:58 +02:00
< ? php
/**
2016-07-08 19:06:35 +02:00
* RssBridgeYoutube
2013-08-15 12:05:58 +02:00
* Returns the newest videos
2015-11-01 12:17:36 +01:00
* WARNING : to parse big playlists ( over ~ 90 videos ), you need to edit simple_html_dom . php :
2014-05-14 14:34:06 +02:00
* change : define ( 'MAX_FILE_SIZE' , 600000 );
* into : define ( 'MAX_FILE_SIZE' , 900000 ); ( or more )
2013-08-15 12:05:58 +02:00
*/
2015-11-01 12:17:36 +01:00
class YoutubeBridge extends BridgeAbstract {
2016-08-30 11:23:55 +02:00
const NAME = 'YouTube Bridge' ;
const URI = 'https://www.youtube.com/' ;
2016-09-25 17:04:28 +02:00
const CACHE_TIMEOUT = 10800 ; // 3h
2016-08-30 11:23:55 +02:00
const DESCRIPTION = 'Returns the 10 newest videos by username/channel/playlist or search' ;
const MAINTAINER = 'mitsukarenai' ;
2015-11-01 12:17:36 +01:00
2016-08-30 11:23:55 +02:00
const PARAMETERS = array (
2016-08-27 21:03:26 +02:00
'By username' => array (
'u' => array (
'name' => 'username' ,
'exampleValue' => 'test' ,
'required' => true
)
),
'By channel id' => array (
'c' => array (
'name' => 'channel id' ,
'exampleValue' => " 15 " ,
'required' => true
)
),
'By playlist Id' => array (
'p' => array (
'name' => 'playlist id' ,
'exampleValue' => " 15 "
)
),
'Search result' => array (
's' => array (
'name' => 'search keyword' ,
'exampleValue' => 'test'
),
'pa' => array (
'name' => 'page' ,
'type' => 'number' ,
'exampleValue' => 1
)
)
);
2015-11-01 12:17:36 +01:00
2016-05-03 23:45:32 +02:00
private function ytBridgeQueryVideoInfo ( $vid , & $author , & $desc , & $time ) {
2016-08-30 11:23:55 +02:00
$html = $this -> getSimpleHTMLDOM ( self :: URI . " watch?v= $vid " );
2016-05-03 23:45:32 +02:00
$author = $html -> innertext ;
$author = substr ( $author , strpos ( $author , '"author=' ) + 8 );
$author = substr ( $author , 0 , strpos ( $author , '\u0026' ));
$desc = $html -> find ( 'div#watch-description-text' , 0 ) -> innertext ;
$time = strtotime ( $html -> find ( 'meta[itemprop=datePublished]' , 0 ) -> getAttribute ( 'content' ));
}
2014-06-20 16:41:51 +02:00
2016-05-03 23:45:32 +02:00
private function ytBridgeAddItem ( $vid , $title , $author , $desc , $time ) {
2016-08-22 18:55:59 +02:00
$item = array ();
$item [ 'id' ] = $vid ;
$item [ 'title' ] = $title ;
$item [ 'author' ] = $author ;
$item [ 'timestamp' ] = $time ;
2016-08-30 11:23:55 +02:00
$item [ 'uri' ] = self :: URI . 'watch?v=' . $vid ;
$thumbnailUri = str_replace ( '/www.' , '/img.' , self :: URI ) . 'vi/' . $vid . '/0.jpg' ;
2016-08-22 18:55:59 +02:00
$item [ 'content' ] = '<a href="' . $item [ 'uri' ] . '"><img src="' . $thumbnailUri . '" /></a><br />' . $desc ;
2016-05-03 23:45:32 +02:00
$this -> items [] = $item ;
}
2014-06-20 16:41:51 +02:00
2016-05-03 23:45:32 +02:00
private function ytBridgeParseXmlFeed ( $xml ) {
foreach ( $xml -> find ( 'entry' ) as $element ) {
2016-05-21 11:45:09 +02:00
$title = $this -> ytBridgeFixTitle ( $element -> find ( 'title' , 0 ) -> plaintext );
2016-05-03 23:45:32 +02:00
$author = $element -> find ( 'name' , 0 ) -> plaintext ;
$desc = $element -> find ( 'media:description' , 0 ) -> innertext ;
$vid = str_replace ( 'yt:video:' , '' , $element -> find ( 'id' , 0 ) -> plaintext );
$time = strtotime ( $element -> find ( 'published' , 0 ) -> plaintext );
$this -> ytBridgeAddItem ( $vid , $title , $author , $desc , $time );
}
2016-05-21 11:45:09 +02:00
$this -> request = $this -> ytBridgeFixTitle ( $xml -> find ( 'feed > title' , 0 ) -> plaintext );
2016-05-03 23:45:32 +02:00
}
2014-05-14 12:39:12 +02:00
2016-05-03 23:45:32 +02:00
private function ytBridgeParseHtmlListing ( $html , $element_selector , $title_selector ) {
$limit = 10 ; $count = 0 ;
foreach ( $html -> find ( $element_selector ) as $element ) {
if ( $count < $limit ) {
$author = '' ; $desc = '' ; $time = 0 ;
$vid = str_replace ( '/watch?v=' , '' , $element -> find ( 'a' , 0 ) -> href );
2016-05-21 11:45:09 +02:00
$title = $this -> ytBridgeFixTitle ( $element -> find ( $title_selector , 0 ) -> plaintext );
if ( $title != '[Private Video]' ) {
$this -> ytBridgeQueryVideoInfo ( $vid , $author , $desc , $time );
$this -> ytBridgeAddItem ( $vid , $title , $author , $desc , $time );
$count ++ ;
}
2014-06-20 17:00:36 +02:00
}
}
2016-05-03 23:45:32 +02:00
}
2016-05-21 11:45:09 +02:00
private function ytBridgeFixTitle ( $title ) {
// convert both Ӓ and " to UTF-8
2016-06-25 10:08:06 +02:00
return html_entity_decode ( $title , ENT_QUOTES , 'UTF-8' );
2016-05-21 11:45:09 +02:00
}
2016-08-25 01:24:53 +02:00
public function collectData (){
2016-05-03 23:45:32 +02:00
$xml = '' ;
$html = '' ;
$url_feed = '' ;
$url_listing = '' ;
2014-05-14 12:39:12 +02:00
2016-08-28 20:38:01 +02:00
if ( $this -> getInput ( 'u' )) { /* User and Channel modes */
2016-08-28 01:25:33 +02:00
$this -> request = $this -> getInput ( 'u' );
2016-08-30 11:23:55 +02:00
$url_feed = self :: URI . 'feeds/videos.xml?user=' . urlencode ( $this -> request );
$url_listing = self :: URI . 'user/' . urlencode ( $this -> request ) . '/videos' ;
2016-08-28 20:38:01 +02:00
} else if ( $this -> getInput ( 'c' )) {
2016-08-28 01:25:33 +02:00
$this -> request = $this -> getInput ( 'c' );
2016-08-30 11:23:55 +02:00
$url_feed = self :: URI . 'feeds/videos.xml?channel_id=' . urlencode ( $this -> request );
$url_listing = self :: URI . 'channel/' . urlencode ( $this -> request ) . '/videos' ;
2016-05-03 23:45:32 +02:00
}
if ( ! empty ( $url_feed ) && ! empty ( $url_listing )) {
2016-07-08 19:06:35 +02:00
if ( $xml = $this -> getSimpleHTMLDOM ( $url_feed )) {
2016-05-03 23:45:32 +02:00
$this -> ytBridgeParseXmlFeed ( $xml );
2016-07-08 19:06:35 +02:00
} else if ( $html = $this -> getSimpleHTMLDOM ( $url_listing )) {
2016-05-03 23:45:32 +02:00
$this -> ytBridgeParseHtmlListing ( $html , 'li.channels-content-item' , 'h3' );
2016-08-17 14:45:08 +02:00
} else $this -> returnServerError ( " Could not request YouTube. Tried: \n - $url_feed\n - $url_listing " );
2014-08-19 21:35:56 +02:00
}
2016-08-28 20:38:01 +02:00
else if ( $this -> getInput ( 'p' )) { /* playlist mode */
2016-08-28 01:25:33 +02:00
$this -> request = $this -> getInput ( 'p' );
2016-08-30 11:23:55 +02:00
$url_listing = self :: URI . 'playlist?list=' . urlencode ( $this -> request );
2016-07-08 19:06:35 +02:00
$html = $this -> getSimpleHTMLDOM ( $url_listing ) or $this -> returnServerError ( " Could not request YouTube. Tried: \n - $url_listing " );
2016-05-03 23:45:32 +02:00
$this -> ytBridgeParseHtmlListing ( $html , 'tr.pl-video' , '.pl-video-title a' );
2016-05-21 11:45:09 +02:00
$this -> request = 'Playlist: ' . str_replace ( ' - YouTube' , '' , $html -> find ( 'title' , 0 ) -> plaintext );
2014-06-20 17:04:27 +02:00
}
2013-08-15 12:05:58 +02:00
2016-08-28 20:38:01 +02:00
else if ( $this -> getInput ( 's' )) { /* search mode */
$this -> request = $this -> getInput ( 's' ); $page = 1 ; if ( $this -> getInput ( 'pa' )) $page = ( int ) preg_replace ( " /[^0-9]/ " , '' , $this -> getInput ( 'pa' ));
2016-08-30 11:23:55 +02:00
$url_listing = self :: URI . 'results?search_query=' . urlencode ( $this -> request ) . '&page=' . $page . '&filters=video&search_sort=video_date_uploaded' ;
2016-07-08 19:06:35 +02:00
$html = $this -> getSimpleHTMLDOM ( $url_listing ) or $this -> returnServerError ( " Could not request YouTube. Tried: \n - $url_listing " );
2016-05-03 23:45:32 +02:00
$this -> ytBridgeParseHtmlListing ( $html , 'div.yt-lockup' , 'h3' );
$this -> request = 'Search: ' . str_replace ( ' - YouTube' , '' , $html -> find ( 'title' , 0 ) -> plaintext );
2014-06-20 17:00:36 +02:00
}
2016-05-03 23:45:32 +02:00
else { /* no valid mode */
2016-08-17 14:45:08 +02:00
$this -> returnClientError ( " You must either specify either: \n - YouTube username (?u=...) \n - Channel id (?c=...) \n - Playlist id (?p=...) \n - Search (?s=...) " );
2016-05-03 23:45:32 +02:00
}
}
2014-06-20 17:00:36 +02:00
public function getName (){
2016-05-03 23:45:32 +02:00
return ( ! empty ( $this -> request ) ? $this -> request . ' - ' : '' ) . 'YouTube Bridge' ;
2014-06-20 17:00:36 +02:00
}
2013-08-15 12:05:58 +02:00
}