From 6bd76af326f88119415212f8fd85bb41598575f4 Mon Sep 17 00:00:00 2001 From: logmanoriginal Date: Sat, 21 Jul 2018 14:22:53 +0200 Subject: [PATCH] [YoutubeBridge] Add duration limits for all modes Adds duration limits (minimum duration, maximum duration) for all modes (user/id/playlist/search). Duration limits are optional, so existing subscriptions don't break. The limits are specified by two separate parameters, each of which is optional: - `&duration_min=` (minimum duration in minutes, default: -1) - `&duration_max=` (maximum duration in minutes, default: INF) If duration limits are specified in either user, id or playlist mode, the bridge defaults to fetching data from HTML intead of XML feeds, which requires more bandwidth and takes longer, because each video is loaded individually! References #670 --- bridges/YoutubeBridge.php | 49 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/bridges/YoutubeBridge.php b/bridges/YoutubeBridge.php index e597fe3a..c021fdc1 100644 --- a/bridges/YoutubeBridge.php +++ b/bridges/YoutubeBridge.php @@ -45,9 +45,25 @@ class YoutubeBridge extends BridgeAbstract { 'type' => 'number', 'exampleValue' => 1 ) + ), + 'global' => array( + 'duration_min' => array( + 'name' => 'min. duration (minutes)', + 'type' => 'number', + 'title' => 'Minimum duration for the video in minutes', + 'exampleValue' => 5 + ), + 'duration_max' => array( + 'name' => 'max. duration (minutes)', + 'type' => 'number', + 'title' => 'Maximum duration for the video in minutes', + 'exampleValue' => 10 + ) ) ); + private $feedName = ''; + private function ytBridgeQueryVideoInfo($vid, &$author, &$desc, &$time){ $html = $this->ytGetSimpleHTMLDOM(self::URI . "watch?v=$vid"); @@ -113,6 +129,17 @@ class YoutubeBridge extends BridgeAbstract { private function ytBridgeParseHtmlListing($html, $element_selector, $title_selector, $add_parsed_items = true) { $limit = $add_parsed_items ? 10 : INF; $count = 0; + + $duration_min = $this->getInput('duration_min') ?: -1; + $duration_min = $duration_min * 60; + + $duration_max = $this->getInput('duration_max') ?: INF; + $duration_max = $duration_max * 60; + + if($duration_max < $duration_min) { + returnClientError('Max duration must be greater than min duration!'); + } + foreach($html->find($element_selector) as $element) { if($count < $limit) { $author = ''; @@ -121,6 +148,20 @@ class YoutubeBridge extends BridgeAbstract { $vid = str_replace('/watch?v=', '', $element->find('a', 0)->href); $vid = substr($vid, 0, strpos($vid, '&') ?: strlen($vid)); $title = $this->ytBridgeFixTitle($element->find($title_selector, 0)->plaintext); + + // The duration comes in one of the formats: + // hh:mm:ss / mm:ss / m:ss + // 01:03:30 / 15:06 / 1:24 + $durationText = trim($element->find('span[class="video-time"]', 0)->plaintext); + $durationText = preg_replace('/([\d]{1,2})\:([\d]{2})/', '00:$1:$2', $durationText); + + sscanf($durationText, '%d:%d:%d', $hours, $minutes, $seconds); + $duration = $hours * 3600 + $minutes * 60 + $seconds; + + if($duration < $duration_min || $duration > $duration_max) { + continue; + } + if($title != '[Private Video]' && strpos($vid, 'googleads') === false) { if ($add_parsed_items) { $this->ytBridgeQueryVideoInfo($vid, $author, $desc, $time); @@ -168,7 +209,7 @@ class YoutubeBridge extends BridgeAbstract { } if(!empty($url_feed) && !empty($url_listing)) { - if($xml = $this->ytGetSimpleHTMLDOM($url_feed)) { + if(!$this->skipFeeds() && $xml = $this->ytGetSimpleHTMLDOM($url_feed)) { $this->ytBridgeParseXmlFeed($xml); } elseif($html = $this->ytGetSimpleHTMLDOM($url_listing)) { $this->ytBridgeParseHtmlListing($html, 'li.channels-content-item', 'h3'); @@ -182,7 +223,7 @@ class YoutubeBridge extends BridgeAbstract { $html = $this->ytGetSimpleHTMLDOM($url_listing) or returnServerError("Could not request YouTube. Tried:\n - $url_listing"); $item_count = $this->ytBridgeParseHtmlListing($html, 'tr.pl-video', '.pl-video-title a', false); - if ($item_count <= 15 && ($xml = $this->ytGetSimpleHTMLDOM($url_feed))) { + if ($item_count <= 15 && !$this->skipFeeds() && ($xml = $this->ytGetSimpleHTMLDOM($url_feed))) { $this->ytBridgeParseXmlFeed($xml); } else { $this->ytBridgeParseHtmlListing($html, 'tr.pl-video', '.pl-video-title a'); @@ -215,6 +256,10 @@ class YoutubeBridge extends BridgeAbstract { } } + private function skipFeeds() { + return ($this->getInput('duration_min') || $this->getInput('duration_max')); + } + public function getName(){ // Name depends on queriedContext: switch($this->queriedContext) {