Browse Source

[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
logmanoriginal 5 years ago
parent
commit
6bd76af326
1 changed files with 47 additions and 2 deletions
  1. 47 2
      bridges/YoutubeBridge.php

+ 47 - 2
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) {