[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
This commit is contained in:
parent
caa622ffec
commit
6bd76af326
1 changed files with 47 additions and 2 deletions
|
@ -45,9 +45,25 @@ class YoutubeBridge extends BridgeAbstract {
|
||||||
'type' => 'number',
|
'type' => 'number',
|
||||||
'exampleValue' => 1
|
'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){
|
private function ytBridgeQueryVideoInfo($vid, &$author, &$desc, &$time){
|
||||||
$html = $this->ytGetSimpleHTMLDOM(self::URI . "watch?v=$vid");
|
$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) {
|
private function ytBridgeParseHtmlListing($html, $element_selector, $title_selector, $add_parsed_items = true) {
|
||||||
$limit = $add_parsed_items ? 10 : INF;
|
$limit = $add_parsed_items ? 10 : INF;
|
||||||
$count = 0;
|
$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) {
|
foreach($html->find($element_selector) as $element) {
|
||||||
if($count < $limit) {
|
if($count < $limit) {
|
||||||
$author = '';
|
$author = '';
|
||||||
|
@ -121,6 +148,20 @@ class YoutubeBridge extends BridgeAbstract {
|
||||||
$vid = str_replace('/watch?v=', '', $element->find('a', 0)->href);
|
$vid = str_replace('/watch?v=', '', $element->find('a', 0)->href);
|
||||||
$vid = substr($vid, 0, strpos($vid, '&') ?: strlen($vid));
|
$vid = substr($vid, 0, strpos($vid, '&') ?: strlen($vid));
|
||||||
$title = $this->ytBridgeFixTitle($element->find($title_selector, 0)->plaintext);
|
$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($title != '[Private Video]' && strpos($vid, 'googleads') === false) {
|
||||||
if ($add_parsed_items) {
|
if ($add_parsed_items) {
|
||||||
$this->ytBridgeQueryVideoInfo($vid, $author, $desc, $time);
|
$this->ytBridgeQueryVideoInfo($vid, $author, $desc, $time);
|
||||||
|
@ -168,7 +209,7 @@ class YoutubeBridge extends BridgeAbstract {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!empty($url_feed) && !empty($url_listing)) {
|
if(!empty($url_feed) && !empty($url_listing)) {
|
||||||
if($xml = $this->ytGetSimpleHTMLDOM($url_feed)) {
|
if(!$this->skipFeeds() && $xml = $this->ytGetSimpleHTMLDOM($url_feed)) {
|
||||||
$this->ytBridgeParseXmlFeed($xml);
|
$this->ytBridgeParseXmlFeed($xml);
|
||||||
} elseif($html = $this->ytGetSimpleHTMLDOM($url_listing)) {
|
} elseif($html = $this->ytGetSimpleHTMLDOM($url_listing)) {
|
||||||
$this->ytBridgeParseHtmlListing($html, 'li.channels-content-item', 'h3');
|
$this->ytBridgeParseHtmlListing($html, 'li.channels-content-item', 'h3');
|
||||||
|
@ -182,7 +223,7 @@ class YoutubeBridge extends BridgeAbstract {
|
||||||
$html = $this->ytGetSimpleHTMLDOM($url_listing)
|
$html = $this->ytGetSimpleHTMLDOM($url_listing)
|
||||||
or returnServerError("Could not request YouTube. Tried:\n - $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);
|
$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);
|
$this->ytBridgeParseXmlFeed($xml);
|
||||||
} else {
|
} else {
|
||||||
$this->ytBridgeParseHtmlListing($html, 'tr.pl-video', '.pl-video-title a');
|
$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(){
|
public function getName(){
|
||||||
// Name depends on queriedContext:
|
// Name depends on queriedContext:
|
||||||
switch($this->queriedContext) {
|
switch($this->queriedContext) {
|
||||||
|
|
Loading…
Reference in a new issue