summaryrefslogtreecommitdiff
path: root/providers
diff options
context:
space:
mode:
authoremkael <emkael@tlen.pl>2025-04-08 02:24:30 +0200
committeremkael <emkael@tlen.pl>2025-04-08 02:24:30 +0200
commitaf150891df3b90fda846941d62ea76616f42a6ab (patch)
tree6363926d7f4a2fe09dc4d1b763b67fbb8d949c09 /providers
parentaf2da903d47550cdf1d7eb2d7b5e5b972d847958 (diff)
Options for YT feeds: minimum video duration and extracting links from descriptionHEADmaster
Diffstat (limited to 'providers')
-rw-r--r--providers/Youtube.php95
1 files changed, 95 insertions, 0 deletions
diff --git a/providers/Youtube.php b/providers/Youtube.php
index bd38a52..03d0e27 100644
--- a/providers/Youtube.php
+++ b/providers/Youtube.php
@@ -3,9 +3,20 @@
namespace Providers;
require_once('Rss.php');
+require_once('../lib/php-youtube-api/src/autoload.php');
class Youtube extends Rss {
+ const DEFAULT_MIN_DURATION = 60;
+
+ public function __construct($feed, $options=[]) {
+ parent::__construct($feed, $options);
+ $config = json_decode(file_get_contents('../config/youtube.json'), TRUE);
+ $this->_youtube = new \Madcoda\Youtube\Youtube([
+ 'key' => $config['key']
+ ]);
+ }
+
protected function _getFeedUrl($feed) {
return 'https://www.youtube.com/feeds/videos.xml?channel_id=' . $feed;
}
@@ -14,6 +25,90 @@ class Youtube extends Rss {
return '../cache/youtube.%s';
}
+ protected function _mapRssItem($item) {
+ $itemObj = parent::_mapRssItem($item);
+ if (array_key_exists('descriptionlink', $this->_options)) {
+ $linkConfig = explode(':', $this->_options['descriptionlink']);
+ $linkDomain = NULL;
+ if (!is_numeric($linkConfig[0])) {
+ $linkDomain = array_shift($linkConfig);
+ if (!$linkConfig) {
+ $linkConfig = ['1'];
+ }
+ }
+ $linkIndex = intval($linkConfig[0]) - 1;
+ $textLinks = [];
+ if (preg_match_all('#(?:(?:https?|ftp):\/\/)?[\w/\-?=%.]+\.[\w/\-&?=%.]+#', $itemObj->Text, $textLinks)) {
+ $textLinks = $textLinks[0];
+ if ($linkDomain) {
+ $textLinks = array_values(array_filter($textLinks, function($link) use($linkDomain) {
+ if($linkParts = parse_url($link)) {
+ return $linkParts['host'] == $linkDomain;
+ }
+ }));
+ }
+ if (count($textLinks) > $linkIndex) {
+ $itemObj->Link = $textLinks[$linkIndex];
+ }
+ }
+ }
+ return $itemObj;
+ }
+
+ private function _getVideoMetadata($ids) {
+ $cacheFile = sprintf($this->_getCachePath() . '.metadata', $this->_feed);
+ $cacheData = [];
+ if (file_exists($cacheFile)) {
+ $cacheData = unserialize(file_get_contents($cacheFile));
+ }
+ $oldIDs = array_keys($cacheData);
+ $newIDs = array_diff($ids, $oldIDs);
+ if ($newIDs) {
+ $metadata = $this->_youtube->getVideosInfo($newIDs);
+ foreach ($metadata as $video) {
+ $cacheData[$video->id] = $video;
+ }
+ }
+ file_put_contents($cacheFile, serialize($cacheData));
+ return array_filter($cacheData, function($item) use($ids) {
+ return in_array($item->id, $ids);
+ });
+ }
+
+ private function _getVideoDurations($ids) {
+ $metadata = $this->_getVideoMetadata($ids);
+ $return = [];
+ foreach ($ids as $id) {
+ $duration = new \DateInterval($metadata[$id]->contentDetails->duration);
+ $return[$id] = $duration->h * 3600 + $duration->i * 60 + $duration->s;
+ }
+ return $return;
+ }
+
+ private function _getVideoID($item) {
+ return preg_replace('/^yt:video:/', '', $item->ID);
+ }
+
+ protected function _filterItemContent($items) {
+ $items = parent::_filterItemContent($items);
+
+ if (array_key_exists('duration', $this->_options)) {
+ $duration = intval($this->_options['duration']);
+ $videoIDs = array_map(array($this, '_getVideoID'), $items);
+ $durations = $this->_getVideoDurations($videoIDs);
+ $minDuration = self::DEFAULT_MIN_DURATION;
+ if (is_numeric($this->_options['duration'])) {
+ $minDuration = intval($this->_options['duration']);
+ }
+ $items = array_filter($items, function($item) use($minDuration, $durations) {
+ $videoID = $this->_getVideoID($item);
+ return $durations[$videoID] >= $minDuration;
+ });
+ }
+
+ return $items;
+ }
+
}
?>