diff --git a/bridges/Arte7Bridge.php b/bridges/Arte7Bridge.php
index 562f648f..08390afa 100644
--- a/bridges/Arte7Bridge.php
+++ b/bridges/Arte7Bridge.php
@@ -1,7 +1,7 @@
array(
+ 'name' => 'Category',
+ 'type' => 'list',
+ 'values' => array(
+ 'All categories' => '',
+ 'Art' => array(
+ 'All' => 'art',
+ 'Classic Art' => 'art.classic-art',
+ 'Classic Finnish Art' => 'art.classic-finnish-art',
+ 'Classic Swedish Art' => 'art.classic-swedish-art',
+ 'Contemporary' => 'art.contemporary',
+ 'Modern Finnish Art' => 'art.modern-finnish-art',
+ 'Modern International Art' => 'art.modern-international-art',
+ 'Modern Swedish Art' => 'art.modern-swedish-art',
+ 'Old Masters' => 'art.old-masters',
+ 'Other' => 'art.other',
+ 'Photographs' => 'art.photographs',
+ 'Prints' => 'art.prints',
+ 'Sculpture' => 'art.sculpture',
+ 'Swedish Old Masters' => 'art.swedish-old-masters',
+ ),
+ 'Asian Ceramics & Works of Art' => array(
+ 'All' => 'asian-ceramics-works-of-art',
+ 'Other' => 'asian-ceramics-works-of-art.other',
+ 'Porcelain' => 'asian-ceramics-works-of-art.porcelain',
+ ),
+ 'Books & Manuscripts' => array(
+ 'All' => 'books-manuscripts',
+ 'Books' => 'books-manuscripts.books',
+ ),
+ 'Carpets, rugs & textiles' => array(
+ 'All' => 'carpets-rugs-textiles',
+ 'European' => 'carpets-rugs-textiles.european',
+ 'Oriental' => 'carpets-rugs-textiles.oriental',
+ 'Rest of the world' => 'carpets-rugs-textiles.rest-of-the-world',
+ 'Scandinavian' => 'carpets-rugs-textiles.scandinavian',
+ ),
+ 'Ceramics & porcelain' => array(
+ 'All' => 'ceramics-porcelain',
+ 'Ceramic ware' => 'ceramics-porcelain.ceramic-ware',
+ 'European' => 'ceramics-porcelain.european',
+ 'Rest of the world' => 'ceramics-porcelain.rest-of-the-world',
+ 'Scandinavian' => 'ceramics-porcelain.scandinavian',
+ ),
+ 'Collectibles' => array(
+ 'All' => 'collectibles',
+ 'Advertising & Retail' => 'collectibles.advertising-retail',
+ 'Memorabilia' => 'collectibles.memorabilia',
+ 'Movies & music' => 'collectibles.movies-music',
+ 'Other' => 'collectibles.other',
+ 'Retro & Popular Culture' => 'collectibles.retro-popular-culture',
+ 'Technica & Nautica' => 'collectibles.technica-nautica',
+ 'Toys' => 'collectibles.toys',
+ ),
+ 'Design' => array(
+ 'All' => 'design',
+ 'Art glass' => 'design.art-glass',
+ 'Furniture' => 'design.furniture',
+ 'Other' => 'design.other',
+ ),
+ 'Folk art' => array(
+ 'All' => 'folk-art',
+ 'All categories' => 'lots',
+ ),
+ 'Furniture' => array(
+ 'All' => 'furniture',
+ 'Armchairs & Sofas' => 'furniture.armchairs-sofas',
+ 'Cabinets & Bureaus' => 'furniture.cabinets-bureaus',
+ 'Chairs' => 'furniture.chairs',
+ 'Garden furniture' => 'furniture.garden-furniture',
+ 'Mirrors' => 'furniture.mirrors',
+ 'Other' => 'furniture.other',
+ 'Shelves & Book cases' => 'furniture.shelves-book-cases',
+ 'Tables' => 'furniture.tables',
+ ),
+ 'Glassware' => array(
+ 'All' => 'glassware',
+ 'Glassware' => 'glassware.glassware',
+ 'Other' => 'glassware.other',
+ ),
+ 'Jewellery' => array(
+ 'All' => 'jewellery',
+ 'Bracelets' => 'jewellery.bracelets',
+ 'Brooches' => 'jewellery.brooches',
+ 'Earrings' => 'jewellery.earrings',
+ 'Necklaces & Pendants' => 'jewellery.necklaces-pendants',
+ 'Other' => 'jewellery.other',
+ 'Rings' => 'jewellery.rings',
+ ),
+ 'Lighting' => array(
+ 'All' => 'lighting',
+ 'Candle sticks & Candelabras' => 'lighting.candle-sticks-candelabras',
+ 'Ceiling lights' => 'lighting.ceiling-lights',
+ 'Chandeliers' => 'lighting.chandeliers',
+ 'Floor lights' => 'lighting.floor-lights',
+ 'Other' => 'lighting.other',
+ 'Table lights' => 'lighting.table-lights',
+ 'Wall lights' => 'lighting.wall-lights',
+ ),
+ 'Militaria' => array(
+ 'All' => 'militaria',
+ 'Honors & Medals' => 'militaria.honors-medals',
+ 'Other militaria' => 'militaria.other-militaria',
+ 'Weaponry' => 'militaria.weaponry',
+ ),
+ 'Miscellaneous' => array(
+ 'All' => 'miscellaneous',
+ 'Brass, Copper & Pewter' => 'miscellaneous.brass-copper-pewter',
+ 'Nickel silver' => 'miscellaneous.nickel-silver',
+ 'Oriental' => 'miscellaneous.oriental',
+ 'Other' => 'miscellaneous.other',
+ ),
+ 'Silver' => array(
+ 'All' => 'silver',
+ 'Candle sticks' => 'silver.candle-sticks',
+ 'Cups & Bowls' => 'silver.cups-bowls',
+ 'Cutlery' => 'silver.cutlery',
+ 'Other' => 'silver.other',
+ ),
+ 'Timepieces' => array(
+ 'All' => 'timepieces',
+ 'Other' => 'timepieces.other',
+ 'Pocket watches' => 'timepieces.pocket-watches',
+ 'Table clocks' => 'timepieces.table-clocks',
+ 'Wrist watches' => 'timepieces.wrist-watches',
+ ),
+ 'Vintage & Fashion' => array(
+ 'All' => 'vintage-fashion',
+ 'Accessories' => 'vintage-fashion.accessories',
+ 'Bags & Trunks' => 'vintage-fashion.bags-trunks',
+ 'Clothes' => 'vintage-fashion.clothes',
+ ),
+ )
+ ),
+ 'sort_order' => array(
+ 'name' => 'Sort order',
+ 'type' => 'list',
+ 'values' => array(
+ 'Ending soon' => 'ending',
+ 'Most recent' => 'recent',
+ 'Most bids' => 'most',
+ 'Fewest bids' => 'fewest',
+ 'Lowest price' => 'lowest',
+ 'Highest price' => 'highest',
+ 'Lowest estimate' => 'low',
+ 'Highest estimate' => 'high',
+ 'Alphabetical' => 'alphabetical',
+ ),
+ ),
+ 'language' => array(
+ 'name' => 'Language',
+ 'type' => 'list',
+ 'values' => array(
+ 'English' => 'en',
+ 'Swedish' => 'sv',
+ 'Finnish' => 'fi'
+ ),
+ ),
+ ));
+
+ const CACHE_TIMEOUT = 3600; // 1 hour
+
+ private $title;
+
+ public function collectData()
+ {
+ $baseUrl = 'https://www.bukowskis.com';
+ $category = $this->getInput('category');
+ $language = $this->getInput('language');
+ $sort_order = $this->getInput('sort_order');
+
+ $url = $baseUrl . '/' . $language . '/lots';
+
+ if ($category)
+ $url = $url . '/category/' . $category;
+
+ if ($sort_order)
+ $url = $url . '/sort/' . $sort_order;
+
+ $html = getSimpleHTMLDOM($url)
+ or returnServerError('Could not request: ' . $url);
+
+ $this->title = htmlspecialchars_decode($html->find('title', 0)->innertext);
+
+ foreach ($html->find('div.c-lot-index-lot') as $lot) {
+ $title = $lot->find('a.c-lot-index-lot__title', 0)->plaintext;
+ $relative_url = $lot->find('a.c-lot-index-lot__link', 0)->href;
+ $images = json_decode(
+ htmlspecialchars_decode(
+ $lot
+ ->find('img.o-aspect-ratio__image', 0)
+ ->getAttribute('data-thumbnails')
+ )
+ );
+
+ $this->items[] = array(
+ 'title' => $title,
+ 'uri' => $baseUrl . $relative_url,
+ 'uid' => $lot->getAttribute('data-lot-id'),
+ 'content' => count($images) > 0 ? "
$title" : $title,
+ 'enclosures' => array_slice($images, 1),
+ );
+ }
+ }
+
+ public function getName()
+ {
+ return $this->title ?: parent::getName();
+ }
+}
diff --git a/bridges/ChristianDailyReporterBridge.php b/bridges/ChristianDailyReporterBridge.php
deleted file mode 100644
index 85f664df..00000000
--- a/bridges/ChristianDailyReporterBridge.php
+++ /dev/null
@@ -1,28 +0,0 @@
-find('div.top p a,div.column p a') as $element) {
- $item = array();
- // Title
- $item['title'] = $element->innertext;
- // URL
- $item['uri'] = $element->href;
- $this->items[] = $item;
- }
- }
-}
diff --git a/bridges/DribbbleBridge.php b/bridges/DribbbleBridge.php
index 01cfb21a..e3452658 100644
--- a/bridges/DribbbleBridge.php
+++ b/bridges/DribbbleBridge.php
@@ -86,7 +86,7 @@ favicon-63b2904a073c89b52b19aa08cebc16a154bcf83fee8ecc6439968b1e6db569c7.ico';
private function getImageTag($preview_path, $title){
return sprintf(
- '
',
+ '
',
$this->getFullSizeImagePath($preview_path),
$preview_path,
$title
@@ -94,6 +94,11 @@ favicon-63b2904a073c89b52b19aa08cebc16a154bcf83fee8ecc6439968b1e6db569c7.ico';
}
private function getFullSizeImagePath($preview_path){
- return explode('?compress=1', $preview_path)[0];
+ // Get last image from srcset
+ $src_set_urls = explode(',', $preview_path);
+ $url = end($src_set_urls);
+ $url = explode(' ', $url)[1];
+
+ return htmlspecialchars_decode($url);
}
}
diff --git a/bridges/ExtremeDownloadBridge.php b/bridges/ExtremeDownloadBridge.php
index bca3997a..9859a2a6 100644
--- a/bridges/ExtremeDownloadBridge.php
+++ b/bridges/ExtremeDownloadBridge.php
@@ -1,7 +1,7 @@
array(
+ 'categories' => array(
+ 'name' => 'Blog categories',
+ 'exampleValue' => 'home-security',
+ ),
+ 'language' => array(
+ 'name' => 'Language',
+ 'defaultValue' => 'en',
+ ),
+ 'oldest_date' => array(
+ 'name' => 'Oldest article date',
+ 'exampleValue' => '-2 months',
+ ),
+ )
+ );
+
+ public function getURI() {
+ $lang = $this->getInput('language') or 'en';
+ if ($lang === 'en') {
+ return self::URI;
+ }
+ return self::URI . "/$lang";
+ }
+
+ public function collectData() {
+ $this->items = array();
+ $this->seen = array();
+
+ $this->oldest = strtotime($this->getInput('oldest_date')) ?: 0;
+
+ $categories = $this->getInput('categories');
+ if (!empty($categories)) {
+ foreach (explode(',', $categories) as $cat) {
+ if (!empty($cat)) {
+ $this->collectCategory($cat);
+ }
+ }
+ return;
+ }
+
+ $html = getSimpleHTMLDOMCached($this->getURI() . '/');
+
+ foreach ($html->find('ul.c-header-menu-desktop__list li a') as $link) {
+ $url = parse_url($link->href);
+ if (($pos = strpos($url['path'], '/category/')) !== false) {
+ $cat = substr($url['path'], $pos + strlen('/category/'), -1);
+ $this->collectCategory($cat);
+ }
+ }
+ }
+
+ private function collectCategory($category) {
+ $url = $this->getURI() . "/category/$category/";
+ while ($url) {
+ $url = $this->collectListing($url);
+ }
+ }
+
+ // n.b. this relies on articles to be ordered by date so the cutoff works
+ private function collectListing($url) {
+ $html = getSimpleHTMLDOMCached($url, 60 * 60);
+ $items = $html->find('section.b-blog .l-blog__content__listing div.c-listing-item');
+
+ $catName = trim($html->find('section.b-blog .c-blog-header__title', 0)->plaintext);
+
+ foreach ($items as $item) {
+ $url = $item->getAttribute('data-url');
+ if (!$this->collectArticle($url)) {
+ return null; // Too old, stop collecting
+ }
+ }
+
+ // Point's to 404 for non-english blog
+ // $next = $html->find('link[rel=next]', 0);
+ $next = $html->find('ul.page-numbers a.next', 0);
+ return $next ? $next->href : null;
+ }
+
+ // Returns a boolean whether to continue collecting articles
+ // i.e. date is after oldest cutoff
+ private function collectArticle($url) {
+ if (array_key_exists($url, $this->seen)) {
+ return true;
+ }
+ $html = getSimpleHTMLDOMCached($url);
+
+ $rssItem = array( 'uri' => $url, 'uid' => $url );
+ $rssItem['title'] = $html->find('meta[property=og:title]', 0)->content;
+ $dt = $html->find('meta[property=article:published_time]', 0)->content;
+ // Exit if too old
+ if (strtotime($dt) < $this->oldest) {
+ return false;
+ }
+ $rssItem['timestamp'] = $dt;
+ $img = $html->find('meta[property=og:image]', 0);
+ $rssItem['enclosures'] = $img ? array($img->content) : array();
+ $rssItem['author'] = trim($html->find('.c-blog-author__text a', 0)->plaintext);
+ $rssItem['categories'] = array_map(function ($link) {
+ return trim($link->plaintext);
+ }, $html->find('.b-single-header__categories .c-category-list a'));
+ $rssItem['content'] = trim($html->find('article', 0)->innertext);
+
+ $this->items[] = $rssItem;
+ $this->seen[$url] = 1;
+ return true;
+ }
+}
diff --git a/bridges/GithubIssueBridge.php b/bridges/GithubIssueBridge.php
index 29a336bd..46fbc4c1 100644
--- a/bridges/GithubIssueBridge.php
+++ b/bridges/GithubIssueBridge.php
@@ -109,8 +109,7 @@ class GithubIssueBridge extends BridgeAbstract {
}
private function extractIssueComment($issueNbr, $title, $comment){
-
- $uri = $this->buildGitHubIssueCommentUri($issueNbr, $comment->parent->id);
+ $uri = $this->buildGitHubIssueCommentUri($issueNbr, $comment->id);
$author = $comment->find('.author', 0)->plaintext;
@@ -171,9 +170,9 @@ class GithubIssueBridge extends BridgeAbstract {
case 'Project Issues':
foreach($html->find('.js-active-navigation-container .js-navigation-item') as $issue) {
$info = $issue->find('.opened-by', 0);
- $issueNbr = substr(
- trim($info->plaintext), 1, strpos(trim($info->plaintext), ' ')
- );
+
+ preg_match('/\/([0-9]+)$/', $issue->find('a', 0)->href, $match);
+ $issueNbr = $match[1];
$item = array();
$item['content'] = '';
diff --git a/bridges/ReutersBridge.php b/bridges/ReutersBridge.php
new file mode 100644
index 00000000..cb6b4e38
--- /dev/null
+++ b/bridges/ReutersBridge.php
@@ -0,0 +1,246 @@
+ array(
+ 'name' => 'News Feed',
+ 'type' => 'list',
+ 'title' => 'Feeds from Reuters U.S/International edition',
+ 'values' => array(
+ 'Aerospace and Defense' => 'aerospace',
+ 'Business' => 'business',
+ 'China' => 'china',
+ 'Energy' => 'energy',
+ 'Entertainment' => 'chan:8ym8q8dl',
+ 'Environment' => 'chan:6u4f0jgs',
+ 'Health' => 'chan:8hw7807a',
+ 'Lifestyle' => 'life',
+ 'Markets' => 'markets',
+ 'Politics' => 'politics',
+ 'Science' => 'science',
+ 'Special Reports' => 'special-reports',
+ 'Sports' => 'sports',
+ 'Tech' => 'tech',
+ 'Top News' => 'home/topnews',
+ 'UK' => 'chan:61leiu7j',
+ 'USA News' => 'us',
+ 'Wire' => 'wire',
+ 'World' => 'world',
+ )
+ )
+ )
+ );
+
+ /**
+ * Performs an HTTP request to the Reuters API and returns decoded JSON
+ * in the form of an associative array
+ * @param string $feed_uri Parameter string to the Reuters API
+ * @return array
+ */
+ private function getJson($feed_uri)
+ {
+ $uri = "https://wireapi.reuters.com/v8$feed_uri";
+ $returned_data = getContents($uri);
+ return json_decode($returned_data, true);
+ }
+
+ /**
+ * Takes in data from Reuters Wire API and
+ * creates structured data in the form of a list
+ * of story information.
+ * @param array $data JSON collected from the Reuters Wire API
+ */
+ private function processData($data)
+ {
+ /**
+ * Gets a list of wire items which are groups of templates
+ */
+ $reuters_allowed_wireitems = array_filter(
+ $data, function ($wireitem) {
+ return in_array(
+ $wireitem['wireitem_type'],
+ self::ALLOWED_WIREITEM_TYPES
+ );
+ }
+ );
+
+ /*
+ * Gets a list of "Templates", which is data containing a story
+ */
+ $reuters_wireitem_templates = array_reduce(
+ $reuters_allowed_wireitems,
+ function (array $carry, array $wireitem) {
+ $wireitem_templates = $wireitem['templates'];
+ return array_merge(
+ $carry,
+ array_filter(
+ $wireitem_templates, function (
+ array $template_data
+ ) {
+ return in_array(
+ $template_data['type'],
+ self::ALLOWED_TEMPLATE_TYPES
+ );
+ }
+ )
+ );
+ },
+ array()
+ );
+
+ return $reuters_wireitem_templates;
+ }
+
+ private function getArticle($feed_uri)
+ {
+ // This will make another request to API to get full detail of article and author's name.
+ $rawData = $this->getJson($feed_uri);
+ $reuters_wireitems = $rawData['wireitems'];
+ $processedData = $this->processData($reuters_wireitems);
+
+ $first = reset($processedData);
+ $article_content = $first['story']['body_items'];
+ $authorlist = $first['story']['authors'];
+ $category = $first['story']['channel']['name'];
+ $image_list = $first['story']['images'];
+ $img_placeholder = '';
+
+ foreach($image_list as $image) { // Add more image to article.
+ $image_url = $image['url'];
+ $image_caption = $image['caption'];
+ $img = "
";
+ $img_caption = "
$data
"; + break; + case 'heading': + $description = $description . "'; + foreach ($item_list as $item) { + if($item['type'] == 'text') { + $description = $description . $item['content']; + } else { + $description = $description . $item['symbol']; + } + } + $description = $description . '
'; + break; + case 'p_table': + $description = $description . $content['content']; + break; + } + } + + $content_detail = array( + 'content' => $description, + 'author' => $author, + 'category' => $category, + 'images' => $img_placeholder, + ); + return $content_detail; + } + + public function getName() { + return $this->feedName; + } + + public function collectData() + { + $reuters_feed_name = $this->getInput('feed'); + + if(strpos($reuters_feed_name, 'chan:') !== false) { + // Now checking whether that feed has unique ID or not. + $feed_uri = "/feed/rapp/us/wirefeed/$reuters_feed_name"; + } else { + $feed_uri = "/feed/rapp/us/tabbar/feeds/$reuters_feed_name"; + } + + $data = $this->getJson($feed_uri); + + $reuters_wireitems = $data['wireitems']; + $this->feedName = $data['wire_name'] . ' | Reuters'; + $processedData = $this->processData($reuters_wireitems); + + // Merge all articles from Editor's Highlight section into existing array of templates. + $top_section = reset($reuters_wireitems); + if ($top_section['wireitem_type'] == 'headlines') { + $top_articles = $top_section['templates'][1]['headlines']; + $processedData = array_merge($top_articles, $processedData); + } + + foreach ($processedData as $story) { + $item['uid'] = $story['story']['usn']; + $article_uri = $story['template_action']['api_path']; + $content_detail = $this->getArticle($article_uri); + $description = $content_detail['content']; + $author = $content_detail['author']; + $images = $content_detail['images']; + $item['categories'] = array($content_detail['category']); + $item['author'] = $author; + if (!(bool) $description) { + $description = $story['story']['lede']; // Just in case the content doesn't have anything. + } else { + $item['content'] = "$description $images"; + } + + $item['title'] = $story['story']['hed']; + $item['timestamp'] = $story['story']['updated_at']; + $item['uri'] = $story['template_action']['url']; + $this->items[] = $item; + } + } +} diff --git a/bridges/ZoneTelechargementBridge.php b/bridges/ZoneTelechargementBridge.php index 06103df0..56c6764a 100644 --- a/bridges/ZoneTelechargementBridge.php +++ b/bridges/ZoneTelechargementBridge.php @@ -8,7 +8,7 @@ class ZoneTelechargementBridge extends BridgeAbstract { */ const NAME = 'Zone Telechargement'; - const URI = 'https://www.zt-za.com/'; + const URI = 'https://www.zt-za.net/'; const DESCRIPTION = 'Suivi de série sur Zone Telechargement'; const MAINTAINER = 'sysadminstory'; const PARAMETERS = array( @@ -34,17 +34,17 @@ class ZoneTelechargementBridge extends BridgeAbstract { ); // This is an URL that is not protected by robot protection for Direct Download - const UNPROTECED_URI = 'https://www.zone-annuaire.com/'; + const UNPROTECTED_URI = 'https://www.zone-telechargement.net/'; // This is an URL that is not protected by robot protection for Streaming Links - const UNPROTECED_URI_STREAMING = 'https://zone-telechargement.stream/'; + const UNPROTECTED_URI_STREAMING = 'https://zone-telechargement.stream/'; public function getIcon() { - return self::UNPROTECED_URI . '/templates/Default/images/favicon.ico'; + return self::UNPROTECTED_URI . '/templates/Default/images/favicon.ico'; } public function collectData(){ - $html = getSimpleHTMLDOM(self::UNPROTECED_URI . $this->getInput('url')) + $html = getSimpleHTMLDOM(self::UNPROTECTED_URI . $this->getInput('url')) or returnServerError('Could not request Zone Telechargement.'); $filter = $this->getInput('filter'); @@ -79,7 +79,7 @@ class ZoneTelechargementBridge extends BridgeAbstract { // Handle the Streaming links if($filter == 'both' || $filter == 'streaming') { // Get the post content, on the dedicated streaming website - $htmlstreaming = getSimpleHTMLDOM(self::UNPROTECED_URI_STREAMING . $this->getInput('url')) + $htmlstreaming = getSimpleHTMLDOM(self::UNPROTECTED_URI_STREAMING . $this->getInput('url')) or returnServerError('Could not request Zone Telechargement.'); // Get the HTML element containing all the links $streaminglinkshtml = $htmlstreaming->find('p[style=background-color: #FECC00;]', 1)->parent()->next_sibling(); diff --git a/lib/BridgeCard.php b/lib/BridgeCard.php index 0ed605bf..69c67bc4 100644 --- a/lib/BridgeCard.php +++ b/lib/BridgeCard.php @@ -347,11 +347,13 @@ This bridge is not fetching its content through a secure connection'; CARD; // If we don't have any parameter for the bridge, we print a generic form to load it. - if(count($parameters) === 0 - || count($parameters) === 1 && array_key_exists('global', $parameters)) { - + if (count($parameters) === 0) { $card .= self::getForm($bridgeName, $formats, $isActive, $isHttps); + // Display form with cache timeout and/or noproxy options (if enabled) when bridge has no parameters + } else if (count($parameters) === 1 && array_key_exists('global', $parameters)) { + $card .= self::getForm($bridgeName, $formats, $isActive, $isHttps, '', $parameters['global']); + } else { foreach($parameters as $parameterName => $parameter) {