From 49da67cb33669c07c8a0ab5d4716e22be807a654 Mon Sep 17 00:00:00 2001 From: Roliga Date: Mon, 26 Nov 2018 18:05:41 +0100 Subject: [PATCH] core: Automatically select a bridge based on a URL (#928) * core: Add bridge parameter auto detection This adds a new 'detect' action which accepts a URL from which an appropriate bridge is selected and relevant parameters are extracted. The user is then automatically redirected to the selected bridge. For example to get a feed from: https://twitter.com/search?q=%23rss-bridge we could send a request to: '/?action=detect&format=Atom&url=twitter.com/search%3Fq%3D%2523rss-bridge' which would redirect to: '/?action=display&q=%23rss-bridge&bridge=Twitter&format=Atom'. This auto detection happens on a per-bridge basis, so a new function 'detectParameters' is added to BridgeInterface which bridges may implement. It takes a URL for an argument and returns a list of parameters that were extracted, or null if the URL isn't relevant for the bridge. * [TwitterBridge] Add parameter auto detection * [BridgeAbstract] Add generic parameter detection This adds generic "paramater detection" for bridges that don't have any parameters defined. If the queried URL matches the URI defined in the bridge (ignoring https://, www. and trailing /) an emtpy list of parameters is returned. --- bridges/TwitterBridge.php | 35 +++++++++++++++++++++++++++++++++++ index.php | 36 ++++++++++++++++++++++++++++++++++++ lib/BridgeAbstract.php | 13 +++++++++++++ lib/BridgeInterface.php | 8 ++++++++ 4 files changed, 92 insertions(+) diff --git a/bridges/TwitterBridge.php b/bridges/TwitterBridge.php index fc7b78bd..20f90d74 100644 --- a/bridges/TwitterBridge.php +++ b/bridges/TwitterBridge.php @@ -66,6 +66,41 @@ class TwitterBridge extends BridgeAbstract { ) ); + public function detectParameters($url){ + $params = array(); + + // By keyword or hashtag (search) + $regex = '/^(https?:\/\/)?(www\.)?twitter\.com\/search.*(\?|&)q=([^\/&?\n]+)/'; + if(preg_match($regex, $url, $matches) > 0) { + $params['q'] = urldecode($matches[4]); + return $params; + } + + // By hashtag + $regex = '/^(https?:\/\/)?(www\.)?twitter\.com\/hashtag\/([^\/?\n]+)/'; + if(preg_match($regex, $url, $matches) > 0) { + $params['q'] = urldecode($matches[3]); + return $params; + } + + // By list + $regex = '/^(https?:\/\/)?(www\.)?twitter\.com\/([^\/?\n]+)\/lists\/([^\/?\n]+)/'; + if(preg_match($regex, $url, $matches) > 0) { + $params['user'] = urldecode($matches[3]); + $params['list'] = urldecode($matches[4]); + return $params; + } + + // By username + $regex = '/^(https?:\/\/)?(www\.)?twitter\.com\/([^\/?\n]+)/'; + if(preg_match($regex, $url, $matches) > 0) { + $params['u'] = urldecode($matches[3]); + return $params; + } + + return null; + } + public function getName(){ switch($this->queriedContext) { case 'By keyword or hashtag': diff --git a/index.php b/index.php index c093644a..772f4942 100644 --- a/index.php +++ b/index.php @@ -96,6 +96,42 @@ try { header('Content-Type: application/json'); echo json_encode($list, JSON_PRETTY_PRINT); + } elseif($action === 'detect') { + + $targetURL = $params['url'] + or returnClientError('You must specify a url!'); + + $format = $params['format'] + or returnClientError('You must specify a format!'); + + foreach(Bridge::listBridges() as $bridgeName) { + + if(!Bridge::isWhitelisted($bridgeName)) { + continue; + } + + $bridge = Bridge::create($bridgeName); + + if($bridge === false) { + continue; + } + + $bridgeParams = $bridge->detectParameters($targetURL); + + if(is_null($bridgeParams)) { + continue; + } + + $bridgeParams['bridge'] = $bridgeName; + $bridgeParams['format'] = $format; + + header('Location: ?action=display&' . http_build_query($bridgeParams), true, 301); + die(); + + } + + returnClientError('No bridge found for given URL: ' . $targetURL); + } elseif($action === 'display' && !empty($bridge)) { $format = $params['format'] diff --git a/lib/BridgeAbstract.php b/lib/BridgeAbstract.php index b02280e4..a2b15802 100644 --- a/lib/BridgeAbstract.php +++ b/lib/BridgeAbstract.php @@ -278,4 +278,17 @@ abstract class BridgeAbstract implements BridgeInterface { return static::CACHE_TIMEOUT; } + /** {@inheritdoc} */ + public function detectParameters($url){ + $regex = '/^(https?:\/\/)?(www\.)?(.+?)(\/)?$/'; + if(empty(static::PARAMETERS) + && preg_match($regex, $url, $urlMatches) > 0 + && preg_match($regex, static::URI, $bridgeUriMatches) > 0 + && $urlMatches[3] === $bridgeUriMatches[3]) { + return array(); + } else { + return null; + } + } + } diff --git a/lib/BridgeInterface.php b/lib/BridgeInterface.php index bc48fe04..803bb3cd 100644 --- a/lib/BridgeInterface.php +++ b/lib/BridgeInterface.php @@ -114,4 +114,12 @@ interface BridgeInterface { * @return int Cache timeout */ public function getCacheTimeout(); + + /** + * Returns parameters from given URL or null if URL is not applicable + * + * @param string $url URL to extract parameters from + * @return array|null List of bridge parameters or null if detection failed. + */ + public function detectParameters($url); }