diff options
author | Johannes 'josch' Schauer <josch@debian.org> | 2020-02-22 18:04:35 +0100 |
---|---|---|
committer | Johannes 'josch' Schauer <josch@debian.org> | 2020-02-22 18:04:35 +0100 |
commit | 779ac0902d2586e1ac31ad41881d8922ec40a7ea (patch) | |
tree | 692cccf44eccc86c0b19e7d1e3baaca8e871c173 | |
parent | 550e60ae0c7e181f945a5dd54bd5e0c85939890a (diff) |
New upstream version 2019-12-01+dfsg1
99 files changed, 10251 insertions, 656 deletions
@@ -2,7 +2,7 @@ === [![LICENSE](https://img.shields.io/badge/license-UNLICENSE-blue.svg)](UNLICENSE) [![GitHub release](https://img.shields.io/github/release/rss-bridge/rss-bridge.svg?logo=github)](https://github.com/rss-bridge/rss-bridge/releases/latest) [![Debian Release](https://img.shields.io/badge/dynamic/json.svg?logo=debian&label=debian%20release&url=https%3A%2F%2Fsources.debian.org%2Fapi%2Fsrc%2Frss-bridge%2F&query=%24.versions%5B0%5D.version&colorB=blue)](https://tracker.debian.org/pkg/rss-bridge) [![Guix Release](https://img.shields.io/badge/guix%20release-unknown-blue.svg)](https://www.gnu.org/software/guix/packages/R/) [![Build Status](https://travis-ci.org/RSS-Bridge/rss-bridge.svg?branch=master)](https://travis-ci.org/RSS-Bridge/rss-bridge) [![Docker Build Status](https://img.shields.io/docker/build/rssbridge/rss-bridge.svg?logo=docker)](https://hub.docker.com/r/rssbridge/rss-bridge/) -RSS-Bridge is a PHP project capable of generating RSS and Atom feeds for websites which don't have one. It can be used on webservers or as stand alone application in CLI mode. +RSS-Bridge is a PHP project capable of generating RSS and Atom feeds for websites that don't have one. It can be used on webservers or as a stand-alone application in CLI mode. **Important**: RSS-Bridge is __not__ a feed reader or feed aggregator, but a tool to generate feeds that are consumed by feed readers and feed aggregators. Find a list of feed aggregators on [Wikipedia](https://en.wikipedia.org/wiki/Comparison_of_feed_aggregators). @@ -76,7 +76,7 @@ RSS-Bridge allows you to take full control over which bridges are displayed to t Find more information on the [Wiki](https://github.com/RSS-Bridge/rss-bridge/wiki/Whitelisting) -**Notice**: By default RSS-Bridge will only show a small subset of bridges. Make sure to read up on [whitelisting](https://github.com/RSS-Bridge/rss-bridge/wiki/Whitelisting) to unlock the full potential of RSS-Bridge! +**Notice**: By default, RSS-Bridge will only show a small subset of bridges. Make sure to read up on [whitelisting](https://github.com/RSS-Bridge/rss-bridge/wiki/Whitelisting) to unlock the full potential of RSS-Bridge! Deploy === @@ -118,6 +118,7 @@ https://gist.github.com/LogMANOriginal/da00cd1e5f0ca31cef8e193509b17fd8 * [alex73](https://github.com/alex73) * [alexAubin](https://github.com/alexAubin) * [AmauryCarrade](https://github.com/AmauryCarrade) +* [AntoineTurmel](https://github.com/AntoineTurmel) * [ArthurHoaro](https://github.com/ArthurHoaro) * [Astalaseven](https://github.com/Astalaseven) * [Astyan-42](https://github.com/Astyan-42) @@ -131,6 +132,7 @@ https://gist.github.com/LogMANOriginal/da00cd1e5f0ca31cef8e193509b17fd8 * [cnlpete](https://github.com/cnlpete) * [corenting](https://github.com/corenting) * [couraudt](https://github.com/couraudt) +* [cyberjacob](https://github.com/cyberjacob) * [da2x](https://github.com/da2x) * [Daiyousei](https://github.com/Daiyousei) * [dawidsowa](https://github.com/dawidsowa) @@ -138,6 +140,7 @@ https://gist.github.com/LogMANOriginal/da00cd1e5f0ca31cef8e193509b17fd8 * [DJCrashdummy](https://github.com/DJCrashdummy) * [Djuuu](https://github.com/Djuuu) * [DnAp](https://github.com/DnAp) +* [dominik-th](https://github.com/dominik-th) * [Draeli](https://github.com/Draeli) * [Dreckiger-Dan](https://github.com/Dreckiger-Dan) * [em92](https://github.com/em92) @@ -149,6 +152,7 @@ https://gist.github.com/LogMANOriginal/da00cd1e5f0ca31cef8e193509b17fd8 * [fulmeek](https://github.com/fulmeek) * [Ginko-Aloe](https://github.com/Ginko-Aloe) * [Glandos](https://github.com/Glandos) +* [gloony](https://github.com/gloony) * [GregThib](https://github.com/GregThib) * [griffaurel](https://github.com/griffaurel) * [Grummfy](https://github.com/Grummfy) @@ -169,11 +173,12 @@ https://gist.github.com/LogMANOriginal/da00cd1e5f0ca31cef8e193509b17fd8 * [laBecasse](https://github.com/laBecasse) * [lagaisse](https://github.com/lagaisse) * [lalannev](https://github.com/lalannev) -* [Leomaradan](https://github.com/Leomaradan) * [ldidry](https://github.com/ldidry) +* [Leomaradan](https://github.com/Leomaradan) * [Limero](https://github.com/Limero) * [LogMANOriginal](https://github.com/LogMANOriginal) * [lorenzos](https://github.com/lorenzos) +* [lukasklinger](https://github.com/lukasklinger) * [m0zes](https://github.com/m0zes) * [matthewseal](https://github.com/matthewseal) * [mcbyte-it](https://github.com/mcbyte-it) @@ -189,6 +194,8 @@ https://gist.github.com/LogMANOriginal/da00cd1e5f0ca31cef8e193509b17fd8 * [niawag](https://github.com/niawag) * [Nono-m0le](https://github.com/Nono-m0le) * [ObsidianWitch](https://github.com/ObsidianWitch) +* [OliverParoczai](https://github.com/OliverParoczai) +* [oratosquilla-oratoria](https://github.com/oratosquilla-oratoria) * [ORelio](https://github.com/ORelio) * [PaulVayssiere](https://github.com/PaulVayssiere) * [pellaeon](https://github.com/pellaeon) @@ -204,16 +211,20 @@ https://gist.github.com/LogMANOriginal/da00cd1e5f0ca31cef8e193509b17fd8 * [rogerdc](https://github.com/rogerdc) * [Roliga](https://github.com/Roliga) * [sebsauvage](https://github.com/sebsauvage) +* [shutosg](https://github.com/shutosg) * [somini](https://github.com/somini) * [squeek502](https://github.com/squeek502) +* [stjohnjohnson](https://github.com/stjohnjohnson) * [Strubbl](https://github.com/Strubbl) * [sublimz](https://github.com/sublimz) +* [sunchaserinfo](https://github.com/sunchaserinfo) * [sysadminstory](https://github.com/sysadminstory) * [tameroski](https://github.com/tameroski) * [teromene](https://github.com/teromene) * [thefranke](https://github.com/thefranke) * [ThePadawan](https://github.com/ThePadawan) * [TheRadialActive](https://github.com/TheRadialActive) +* [TitiTestScalingo](https://github.com/TitiTestScalingo) * [triatic](https://github.com/triatic) * [VerifiedJoseph](https://github.com/VerifiedJoseph) * [WalterBarrett](https://github.com/WalterBarrett) diff --git a/actions/ConnectivityAction.php b/actions/ConnectivityAction.php new file mode 100644 index 0000000..69272dd --- /dev/null +++ b/actions/ConnectivityAction.php @@ -0,0 +1,136 @@ +<?php +/** + * This file is part of RSS-Bridge, a PHP project capable of generating RSS and + * Atom feeds for websites that don't have one. + * + * For the full license information, please view the UNLICENSE file distributed + * with this source code. + * + * @package Core + * @license http://unlicense.org/ UNLICENSE + * @link https://github.com/rss-bridge/rss-bridge + */ + +/** + * Checks if the website for a given bridge is reachable. + * + * **Remarks** + * - This action is only available in debug mode. + * - Returns the bridge status as Json-formatted string. + * - Returns an error if the bridge is not whitelisted. + * - Returns a responsive web page that automatically checks all whitelisted + * bridges (using JavaScript) if no bridge is specified. + */ +class ConnectivityAction extends ActionAbstract { + public function execute() { + + if(!Debug::isEnabled()) { + returnError('This action is only available in debug mode!'); + } + + if(!isset($this->userData['bridge'])) { + $this->returnEntryPage(); + return; + } + + $bridgeName = $this->userData['bridge']; + + $this->reportBridgeConnectivity($bridgeName); + + } + + /** + * Generates a report about the bridge connectivity status and sends it back + * to the user. + * + * The report is generated as Json-formatted string in the format + * { + * "bridge": "<bridge-name>", + * "successful": true/false + * } + * + * @param string $bridgeName Name of the bridge to generate the report for + * @return void + */ + private function reportBridgeConnectivity($bridgeName) { + + $bridgeFac = new \BridgeFactory(); + $bridgeFac->setWorkingDir(PATH_LIB_BRIDGES); + + if(!$bridgeFac->isWhitelisted($bridgeName)) { + header('Content-Type: text/html'); + returnServerError('Bridge is not whitelisted!'); + } + + header('Content-Type: text/json'); + + $retVal = array( + 'bridge' => $bridgeName, + 'successful' => false, + 'http_code' => 200, + ); + + $bridge = $bridgeFac->create($bridgeName); + + if($bridge === false) { + echo json_encode($retVal); + return; + } + + $curl_opts = array( + CURLOPT_CONNECTTIMEOUT => 5 + ); + + try { + $reply = getContents($bridge::URI, array(), $curl_opts, true); + + if($reply) { + $retVal['successful'] = true; + if (isset($reply['header'])) { + if (strpos($reply['header'], 'HTTP/1.1 301 Moved Permanently') !== false) { + $retVal['http_code'] = 301; + } + } + } + } catch(Exception $e) { + $retVal['successful'] = false; + } + + echo json_encode($retVal); + + } + + private function returnEntryPage() { + echo <<<EOD +<!DOCTYPE html> + +<html> + <head> + <link rel="stylesheet" href="static/bootstrap.min.css"> + <link + rel="stylesheet" + href="https://use.fontawesome.com/releases/v5.6.3/css/all.css" + integrity="sha384-UHRtZLI+pbxtHCWp1t77Bi1L4ZtiqrqD80Kn4Z8NTSRyMA2Fd33n5dQ8lWUE00s/" + crossorigin="anonymous"> + <link rel="stylesheet" href="static/connectivity.css"> + <script src="static/connectivity.js" type="text/javascript"></script> + </head> + <body> + <div id="main-content" class="container"> + <div class="progress"> + <div class="progress-bar" role="progressbar" aria-valuenow="75" aria-valuemin="0" aria-valuemax="100"></div> + </div> + <div id="status-message" class="sticky-top alert alert-primary alert-dismissible fade show" role="alert"> + <i id="status-icon" class="fas fa-sync"></i> + <span>...</span> + <button type="button" class="close" data-dismiss="alert" aria-label="Close" onclick="stopConnectivityChecks()"> + <span aria-hidden="true">×</span> + </button> + </div> + <input type="text" class="form-control" id="search" onkeyup="search()" placeholder="Search for bridge.."> + </div> + </body> +</html> +EOD; + } +} diff --git a/actions/DisplayAction.php b/actions/DisplayAction.php index 9b4d363..89930cf 100644 --- a/actions/DisplayAction.php +++ b/actions/DisplayAction.php @@ -12,6 +12,15 @@ */ class DisplayAction extends ActionAbstract { + private function get_return_code($error) { + $returnCode = $error->getCode(); + if ($returnCode === 301 || $returnCode === 302) { + # Don't pass redirect codes to the exterior + $returnCode = 508; + } + return $returnCode; + } + public function execute() { $bridge = array_key_exists('bridge', $this->userData) ? $this->userData['bridge'] : null; @@ -146,63 +155,77 @@ class DisplayAction extends ActionAbstract { } catch(Error $e) { error_log($e); - $item = new \FeedItem(); - - // Create "new" error message every 24 hours - $this->userData['_error_time'] = urlencode((int)(time() / 86400)); - - // Error 0 is a special case (i.e. "trying to get property of non-object") - if($e->getCode() === 0) { - $item->setTitle( - 'Bridge encountered an unexpected situation! (' - . $this->userData['_error_time'] - . ')' - ); - } else { - $item->setTitle( - 'Bridge returned error ' - . $e->getCode() - . '! (' - . $this->userData['_error_time'] - . ')' - ); + if(logBridgeError($bridge::NAME, $e->getCode()) >= Configuration::getConfig('error', 'report_limit')) { + if(Configuration::getConfig('error', 'output') === 'feed') { + $item = new \FeedItem(); + + // Create "new" error message every 24 hours + $this->userData['_error_time'] = urlencode((int)(time() / 86400)); + + // Error 0 is a special case (i.e. "trying to get property of non-object") + if($e->getCode() === 0) { + $item->setTitle( + 'Bridge encountered an unexpected situation! (' + . $this->userData['_error_time'] + . ')' + ); + } else { + $item->setTitle( + 'Bridge returned error ' + . $e->getCode() + . '! (' + . $this->userData['_error_time'] + . ')' + ); + } + + $item->setURI( + (isset($_SERVER['REQUEST_URI']) ? parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) : '') + . '?' + . http_build_query($this->userData) + ); + + $item->setTimestamp(time()); + $item->setContent(buildBridgeException($e, $bridge)); + + $items[] = $item; + } elseif(Configuration::getConfig('error', 'output') === 'http') { + header('Content-Type: text/html', true, get_return_code($e)); + die(buildTransformException($e, $bridge)); + } } - - $item->setURI( - (isset($_SERVER['REQUEST_URI']) ? parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) : '') - . '?' - . http_build_query($this->userData) - ); - - $item->setTimestamp(time()); - $item->setContent(buildBridgeException($e, $bridge)); - - $items[] = $item; } catch(Exception $e) { error_log($e); - $item = new \FeedItem(); - - // Create "new" error message every 24 hours - $this->userData['_error_time'] = urlencode((int)(time() / 86400)); - - $item->setURI( - (isset($_SERVER['REQUEST_URI']) ? parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) : '') - . '?' - . http_build_query($this->userData) - ); - - $item->setTitle( - 'Bridge returned error ' - . $e->getCode() - . '! (' - . $this->userData['_error_time'] - . ')' - ); - $item->setTimestamp(time()); - $item->setContent(buildBridgeException($e, $bridge)); - - $items[] = $item; + if(logBridgeError($bridge::NAME, $e->getCode()) >= Configuration::getConfig('error', 'report_limit')) { + if(Configuration::getConfig('error', 'output') === 'feed') { + $item = new \FeedItem(); + + // Create "new" error message every 24 hours + $this->userData['_error_time'] = urlencode((int)(time() / 86400)); + + $item->setURI( + (isset($_SERVER['REQUEST_URI']) ? parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) : '') + . '?' + . http_build_query($this->userData) + ); + + $item->setTitle( + 'Bridge returned error ' + . $e->getCode() + . '! (' + . $this->userData['_error_time'] + . ')' + ); + $item->setTimestamp(time()); + $item->setContent(buildBridgeException($e, $bridge)); + + $items[] = $item; + } elseif(Configuration::getConfig('error', 'output') === 'http') { + header('Content-Type: text/html', true, get_return_code($e)); + die(buildTransformException($e, $bridge)); + } + } } // Store data in cache diff --git a/bridges/AmazonPriceTrackerBridge.php b/bridges/AmazonPriceTrackerBridge.php index 6fa11c9..950178a 100644 --- a/bridges/AmazonPriceTrackerBridge.php +++ b/bridges/AmazonPriceTrackerBridge.php @@ -134,11 +134,11 @@ EOT; // data-asin="B00WTHJ5SU" data-asin-price="14.99" data-asin-shipping="0" // data-asin-currency-code="USD" data-substitute-count="-1" ... /> if ($asinData) { - return [ + return array( 'price' => $asinData->getAttribute('data-asin-price'), 'currency' => $asinData->getAttribute('data-asin-currency-code'), 'shipping' => $asinData->getAttribute('data-asin-shipping') - ]; + ); } return false; @@ -150,11 +150,11 @@ EOT; preg_match('/^\s*([A-Z]{3}|£|\$)\s?([\d.,]+)\s*$/', $priceDiv->plaintext, $matches); if (count($matches) === 3) { - return [ + return array( 'price' => $matches[2], 'currency' => $matches[1], 'shipping' => '0' - ]; + ); } return false; diff --git a/bridges/AppleAppStoreBridge.php b/bridges/AppleAppStoreBridge.php new file mode 100644 index 0000000..c1403fe --- /dev/null +++ b/bridges/AppleAppStoreBridge.php @@ -0,0 +1,149 @@ +<?php + +class AppleAppStoreBridge extends BridgeAbstract { + + const MAINTAINER = 'captn3m0'; + const NAME = 'Apple App Store'; + const URI = 'https://apps.apple.com/'; + const CACHE_TIMEOUT = 3600; // 1h + const DESCRIPTION = 'Returns version updates for a specific application'; + + const PARAMETERS = array(array( + 'id' => array( + 'name' => 'Application ID', + 'required' => true, + 'exampleValue' => '310633997' + ), + 'p' => array( + 'name' => 'Platform', + 'type' => 'list', + 'values' => array( + 'iPad' => 'ipad', + 'iPhone' => 'iphone', + 'Mac' => 'mac', + + // The following 2 are present in responses + // but not yet tested + 'Web' => 'web', + 'Apple TV' => 'appletv', + ), + 'defaultValue' => 'iphone', + ), + 'country' => array( + 'name' => 'Store Country', + 'type' => 'list', + 'values' => array( + 'US' => 'US', + 'India' => 'IN', + 'Canada' => 'CA' + ), + 'defaultValue' => 'US', + ), + )); + + const PLATFORM_MAPPING = array( + 'iphone' => 'ios', + 'ipad' => 'ios', + ); + + private function makeHtmlUrl($id, $country){ + return 'https://apps.apple.com/' . $country . '/app/id' . $id; + } + + private function makeJsonUrl($id, $platform, $country){ + return "https://amp-api.apps.apple.com/v1/catalog/$country/apps/$id?platform=$platform&extend=versionHistory"; + } + + public function getName(){ + if (isset($this->name)) { + return $this->name . ' - AppStore Updates'; + } + + return parent::getName(); + } + + /** + * In case of some platforms, the data is present in the initial response + */ + private function getDataFromShoebox($id, $platform, $country){ + $uri = $this->makeHtmlUrl($id, $country); + $html = getSimpleHTMLDOMCached($uri, 3600); + $script = $html->find('script[id="shoebox-ember-data-store"]', 0); + + $json = json_decode($script->innertext, true); + return $json['data']; + } + + private function getJWTToken($id, $platform, $country){ + $uri = $this->makeHtmlUrl($id, $country); + + $html = getSimpleHTMLDOMCached($uri, 3600); + + $meta = $html->find('meta[name="web-experience-app/config/environment"]', 0); + + $json = urldecode($meta->content); + + $json = json_decode($json); + + return $json->MEDIA_API->token; + } + + private function getAppData($id, $platform, $country, $token){ + $uri = $this->makeJsonUrl($id, $platform, $country); + + $headers = array( + "Authorization: Bearer $token", + ); + + $json = json_decode(getContents($uri, $headers), true); + + return $json['data'][0]; + } + + /** + * Parses the version history from the data received + * @return array list of versions with details on each element + */ + private function getVersionHistory($data, $platform){ + switch($platform) { + case 'mac': + return $data['relationships']['platforms']['data'][0]['attributes']['versionHistory']; + default: + $os = self::PLATFORM_MAPPING[$platform]; + return $data['attributes']['platformAttributes'][$os]['versionHistory']; + } + } + + public function collectData() { + $id = $this->getInput('id'); + $country = $this->getInput('country'); + $platform = $this->getInput('p'); + + switch ($platform) { + case 'mac': + $data = $this->getDataFromShoebox($id, $platform, $country); + break; + + default: + $token = $this->getJWTToken($id, $platform, $country); + $data = $this->getAppData($id, $platform, $country, $token); + } + + $versionHistory = $this->getVersionHistory($data, $platform); + $name = $this->name = $data['attributes']['name']; + $author = $data['attributes']['artistName']; + + foreach ($versionHistory as $row) { + $item = array(); + + $item['content'] = nl2br($row['releaseNotes']); + $item['title'] = $name . ' - ' . $row['versionDisplay']; + $item['timestamp'] = $row['releaseDate']; + $item['author'] = $author; + + $item['uri'] = $this->makeHtmlUrl($id, $country); + + $this->items[] = $item; + } + } +} diff --git a/bridges/AppleMusicBridge.php b/bridges/AppleMusicBridge.php index 5a4f40a..3011977 100644 --- a/bridges/AppleMusicBridge.php +++ b/bridges/AppleMusicBridge.php @@ -5,19 +5,19 @@ class AppleMusicBridge extends BridgeAbstract { const URI = 'https://www.apple.com'; const DESCRIPTION = 'Fetches the latest releases from an artist'; const MAINTAINER = 'Limero'; - const PARAMETERS = [[ - 'url' => [ + const PARAMETERS = array(array( + 'url' => array( 'name' => 'Artist URL', 'exampleValue' => 'https://itunes.apple.com/us/artist/dunderpatrullen/329796274', 'required' => true, - ], - 'imgSize' => [ + ), + 'imgSize' => array( 'name' => 'Image size for thumbnails (in px)', 'type' => 'number', 'defaultValue' => 512, 'required' => true, - ] - ]]; + ) + )); const CACHE_TIMEOUT = 21600; // 6 hours public function collectData() { @@ -36,12 +36,12 @@ class AppleMusicBridge extends BridgeAbstract { // Loop through each object foreach ($json->included as $obj) { if ($obj->type === 'lockup/album') { - $this->items[] = [ + $this->items[] = array( 'title' => $obj->attributes->artistName . ' - ' . $obj->attributes->name, 'uri' => $obj->attributes->url, 'timestamp' => $obj->attributes->releaseDate, 'enclosures' => $obj->relationships->artwork->data->id, - ]; + ); } elseif ($obj->type === 'image') { $images[$obj->id] = $obj->attributes->url; } @@ -49,9 +49,9 @@ class AppleMusicBridge extends BridgeAbstract { // Add the images to each item foreach ($this->items as &$item) { - $item['enclosures'] = [ + $item['enclosures'] = array( str_replace('{w}x{h}bb.{f}', $imgSize . 'x0w.jpg', $images[$item['enclosures']]), - ]; + ); } // Sort the order to put the latest albums first diff --git a/bridges/AtmoNouvelleAquitaineBridge.php b/bridges/AtmoNouvelleAquitaineBridge.php index 2ded81a..d395fa7 100644 --- a/bridges/AtmoNouvelleAquitaineBridge.php +++ b/bridges/AtmoNouvelleAquitaineBridge.php @@ -77,7 +77,7 @@ class AtmoNouvelleAquitaineBridge extends BridgeAbstract { private function getLegendIndexes() { $rawIndexes = $this->dom->find('.prevision-legend .prevision-legend-label'); - $indexes = []; + $indexes = array(); for ($i = 0; $i < count($rawIndexes); $i++) { if ($rawIndexes[$i]->hasAttribute('data-color')) { $indexes[$rawIndexes[$i]->getAttribute('data-color')] = $rawIndexes[$i]->innertext; diff --git a/bridges/BandcampBridge.php b/bridges/BandcampBridge.php index 6c75ed5..fa07146 100644 --- a/bridges/BandcampBridge.php +++ b/bridges/BandcampBridge.php @@ -1,71 +1,260 @@ <?php class BandcampBridge extends BridgeAbstract { - const MAINTAINER = 'sebsauvage'; - const NAME = 'Bandcamp Tag'; + const MAINTAINER = 'sebsauvage, Roliga'; + const NAME = 'Bandcamp Bridge'; const URI = 'https://bandcamp.com/'; const CACHE_TIMEOUT = 600; // 10min - const DESCRIPTION = 'New bandcamp release by tag'; - const PARAMETERS = array( array( - 'tag' => array( - 'name' => 'tag', - 'type' => 'text', - 'required' => true + const DESCRIPTION = 'New bandcamp releases by tag, band or album'; + const PARAMETERS = array( + 'By tag' => array( + 'tag' => array( + 'name' => 'tag', + 'type' => 'text', + 'required' => true + ) + ), + 'By band' => array( + 'band' => array( + 'name' => 'band', + 'type' => 'text', + 'title' => 'Band name as seen in the band page URL', + 'required' => true + ), + 'type' => array( + 'name' => 'Articles are', + 'type' => 'list', + 'values' => array( + 'Releases' => 'releases', + 'Releases, new one when track list changes' => 'changes', + 'Individual tracks' => 'tracks' + ), + 'defaultValue' => 'changes' + ), + 'limit' => array( + 'name' => 'limit', + 'type' => 'number', + 'title' => 'Number of releases to return', + 'defaultValue' => 5 + ) + ), + 'By album' => array( + 'band' => array( + 'name' => 'band', + 'type' => 'text', + 'title' => 'Band name as seen in the album page URL', + 'required' => true + ), + 'album' => array( + 'name' => 'album', + 'type' => 'text', + 'title' => 'Album name as seen in the album page URL', + 'required' => true + ), + 'type' => array( + 'name' => 'Articles are', + 'type' => 'list', + 'values' => array( + 'Releases' => 'releases', + 'Releases, new one when track list changes' => 'changes', + 'Individual tracks' => 'tracks' + ), + 'defaultValue' => 'tracks' + ) ) - )); + ); const IMGURI = 'https://f4.bcbits.com/'; const IMGSIZE_300PX = 23; const IMGSIZE_700PX = 16; + private $feedName; + public function getIcon() { return 'https://s4.bcbits.com/img/bc_favicon.ico'; } public function collectData(){ - $url = self::URI . 'api/hub/1/dig_deeper'; - $data = $this->buildRequestJson(); - $header = array( - 'Content-Type: application/json', - 'Content-Length: ' . strlen($data) - ); - $opts = array( - CURLOPT_CUSTOMREQUEST => 'POST', - CURLOPT_POSTFIELDS => $data - ); - $content = getContents($url, $header, $opts) - or returnServerError('Could not complete request to: ' . $url); + switch($this->queriedContext) { + case 'By tag': + $url = self::URI . 'api/hub/1/dig_deeper'; + $data = $this->buildRequestJson(); + $header = array( + 'Content-Type: application/json', + 'Content-Length: ' . strlen($data) + ); + $opts = array( + CURLOPT_CUSTOMREQUEST => 'POST', + CURLOPT_POSTFIELDS => $data + ); + $content = getContents($url, $header, $opts) + or returnServerError('Could not complete request to: ' . $url); + + $json = json_decode($content); + + if ($json->ok !== true) { + returnServerError('Invalid response'); + } + + foreach ($json->items as $entry) { + $url = $entry->tralbum_url; + $artist = $entry->artist; + $title = $entry->title; + // e.g. record label is the releaser, but not the artist + $releaser = $entry->band_name !== $entry->artist ? $entry->band_name : null; + + $full_title = $artist . ' - ' . $title; + $full_artist = $artist; + if (isset($releaser)) { + $full_title .= ' (' . $releaser . ')'; + $full_artist .= ' (' . $releaser . ')'; + } + $small_img = $this->getImageUrl($entry->art_id, self::IMGSIZE_300PX); + $img = $this->getImageUrl($entry->art_id, self::IMGSIZE_700PX); + + $item = array( + 'uri' => $url, + 'author' => $full_artist, + 'title' => $full_title + ); + $item['content'] = "<img src='$small_img' /><br/>$full_title"; + $item['enclosures'] = array($img); + $this->items[] = $item; + } + break; + case 'By band': + case 'By album': + $html = getSimpleHTMLDOMCached($this->getURI(), 86400); + + $titleElement = $html->find('head meta[name=title]', 0) + or returnServerError('Unable to find title on: ' . $this->getURI()); + $this->feedName = $titleElement->content; + + $regex = '/band_id=(\d+)/'; + if(preg_match($regex, $html, $matches) == false) + returnServerError('Unable to find band ID on: ' . $this->getURI()); + $band_id = $matches[1]; + + $tralbums = array(); + switch($this->queriedContext) { + case 'By band': + $query_data = array( + 'band_id' => $band_id + ); + $band_data = $this->apiGet('mobile/22/band_details', $query_data); - $json = json_decode($content); + $num_albums = min(count($band_data->discography), $this->getInput('limit')); + for($i = 0; $i < $num_albums; $i++) { + $album_basic_data = $band_data->discography[$i]; - if ($json->ok !== true) { - returnServerError('Invalid response'); + // 'a' or 't' for albums and individual tracks respectively + $tralbum_type = substr($album_basic_data->item_type, 0, 1); + + $query_data = array( + 'band_id' => $band_id, + 'tralbum_type' => $tralbum_type, + 'tralbum_id' => $album_basic_data->item_id + ); + $tralbums[] = $this->apiGet('mobile/22/tralbum_details', $query_data); + } + break; + case 'By album': + $regex = '/album=(\d+)/'; + if(preg_match($regex, $html, $matches) == false) + returnServerError('Unable to find album ID on: ' . $this->getURI()); + $album_id = $matches[1]; + + $query_data = array( + 'band_id' => $band_id, + 'tralbum_type' => 'a', + 'tralbum_id' => $album_id + ); + $tralbums[] = $this->apiGet('mobile/22/tralbum_details', $query_data); + + break; + } + + foreach ($tralbums as $tralbum_data) { + if ($tralbum_data->type === 'a' && $this->getInput('type') === 'tracks') { + foreach ($tralbum_data->tracks as $track) { + $query_data = array( + 'band_id' => $band_id, + 'tralbum_type' => 't', + 'tralbum_id' => $track->track_id + ); + $track_data = $this->apiGet('mobile/22/tralbum_details', $query_data); + + $this->items[] = $this->buildTralbumItem($track_data); + } + } else { + $this->items[] = $this->buildTralbumItem($tralbum_data); + } + } + break; } + } + + private function buildTralbumItem($tralbum_data){ + $band_data = $tralbum_data->band; + + // Format title like: ARTIST - ALBUM/TRACK (OPTIONAL RELEASER) + // Format artist/author like: ARTIST (OPTIONAL RELEASER) + // + // If the album/track is released under a label/a band other than the artist + // themselves, append that releaser name to the title and artist/author. + // + // This sadly doesn't always work right for individual tracks as the artist + // of the track is always set to the releaser. + $artist = $tralbum_data->tralbum_artist; + $full_title = $artist . ' - ' . $tralbum_data->title; + $full_artist = $artist; + if (isset($tralbum_data->label)) { + $full_title .= ' (' . $tralbum_data->label . ')'; + $full_artist .= ' (' . $tralbum_data->label . ')'; + } elseif ($band_data->name !== $artist) { + $full_title .= ' (' . $band_data->name . ')'; + $full_artist .= ' (' . $band_data->name . ')'; + } + + $small_img = $this->getImageUrl($tralbum_data->art_id, self::IMGSIZE_300PX); + $img = $this->getImageUrl($tralbum_data->art_id, self::IMGSIZE_700PX); + + $item = array( + 'uri' => $tralbum_data->bandcamp_url, + 'author' => $full_artist, + 'title' => $full_title, + 'enclosures' => array($img), + 'timestamp' => $tralbum_data->release_date + ); - foreach ($json->items as $entry) { - $url = $entry->tralbum_url; - $artist = $entry->artist; - $title = $entry->title; - // e.g. record label is the releaser, but not the artist - $releaser = $entry->band_name !== $entry->artist ? $entry->band_name : null; - - $full_title = $artist . ' - ' . $title; - $full_artist = $artist; - if (isset($releaser)) { - $full_title .= ' (' . $releaser . ')'; - $full_artist .= ' (' . $releaser . ')'; + $item['categories'] = array(); + foreach ($tralbum_data->tags as $tag) { + $item['categories'][] = $tag->norm_name; + } + + // Give articles a unique UID depending on its track list + // Releases should then show up as new articles when tracks are added + if ($this->getInput('type') === 'changes') { + $item['uid'] = "bandcamp/$band_data->band_id/$tralbum_data->id/"; + foreach ($tralbum_data->tracks as $track) { + $item['uid'] .= $track->track_id; } - $small_img = $this->getImageUrl($entry->art_id, self::IMGSIZE_300PX); - $img = $this->getImageUrl($entry->art_id, self::IMGSIZE_700PX); + } - $item = array( - 'uri' => $url, - 'author' => $full_artist, - 'title' => $full_title - ); - $item['content'] = "<img src='$small_img' /><br/>$full_title"; - $item['enclosures'] = array($img); - $this->items[] = $item; + $item['content'] = "<img src='$small_img' /><br/>$full_title<br/>"; + if ($tralbum_data->type === 'a') { + $item['content'] .= '<ol>'; + foreach ($tralbum_data->tracks as $track) { + $item['content'] .= "<li>$track->title</li>"; + } + $item['content'] .= '</ol>'; + } + if (!empty($tralbum_data->about)) { + $item['content'] .= '<p>' + . nl2br($tralbum_data->about) + . '</p>'; } + + return $item; } private function buildRequestJson(){ @@ -81,11 +270,94 @@ class BandcampBridge extends BridgeAbstract { return self::IMGURI . 'img/a' . $id . '_' . $size . '.jpg'; } + private function apiGet($endpoint, $query_data) { + $url = self::URI . 'api/' . $endpoint . '?' . http_build_query($query_data); + $data = json_decode(getContents($url)) + or returnServerError('API request to "' . $url . '" failed.'); + return $data; + } + + public function getURI(){ + switch($this->queriedContext) { + case 'By tag': + if(!is_null($this->getInput('tag'))) { + return self::URI + . 'tag/' + . urlencode($this->getInput('tag')) + . '?sort_field=date'; + } + break; + case 'By band': + if(!is_null($this->getInput('band'))) { + return 'https://' + . $this->getInput('band') + . '.bandcamp.com/music'; + } + break; + case 'By album': + if(!is_null($this->getInput('band')) && !is_null($this->getInput('album'))) { + return 'https://' + . $this->getInput('band') + . '.bandcamp.com/album/' + . $this->getInput('album'); + } + break; + } + + return parent::getURI(); + } + public function getName(){ - if(!is_null($this->getInput('tag'))) { - return $this->getInput('tag') . ' - Bandcamp Tag'; + switch($this->queriedContext) { + case 'By tag': + if(!is_null($this->getInput('tag'))) { + return $this->getInput('tag') . ' - Bandcamp Tag'; + } + break; + case 'By band': + if(isset($this->feedName)) { + return $this->feedName . ' - Bandcamp Band'; + } elseif(!is_null($this->getInput('band'))) { + return $this->getInput('band') . ' - Bandcamp Band'; + } + break; + case 'By album': + if(isset($this->feedName)) { + return $this->feedName . ' - Bandcamp Album'; + } elseif(!is_null($this->getInput('album'))) { + return $this->getInput('album') . ' - Bandcamp Album'; + } + break; } return parent::getName(); } + + public function detectParameters($url) { + $params = array(); + + // By tag + $regex = '/^(https?:\/\/)?bandcamp\.com\/tag\/([^\/.&?\n]+)/'; + if(preg_match($regex, $url, $matches) > 0) { + $params['tag'] = urldecode($matches[2]); + return $params; + } + + // By band + $regex = '/^(https?:\/\/)?([^\/.&?\n]+?)\.bandcamp\.com/'; + if(preg_match($regex, $url, $matches) > 0) { + $params['band'] = urldecode($matches[2]); + return $params; + } + + // By album + $regex = '/^(https?:\/\/)?([^\/.&?\n]+?)\.bandcamp\.com\/album\/([^\/.&?\n]+)/'; + if(preg_match($regex, $url, $matches) > 0) { + $params['band'] = urldecode($matches[2]); + $params['album'] = urldecode($matches[3]); + return $params; + } + + return null; + } } diff --git a/bridges/BastaBridge.php b/bridges/BastaBridge.php index 17d3da7..613005f 100644 --- a/bridges/BastaBridge.php +++ b/bridges/BastaBridge.php @@ -3,17 +3,11 @@ class BastaBridge extends BridgeAbstract { const MAINTAINER = 'qwertygc'; const NAME = 'Bastamag Bridge'; - const URI = 'http://www.bastamag.net/'; + const URI = 'https://www.bastamag.net/'; const CACHE_TIMEOUT = 7200; // 2h const DESCRIPTION = 'Returns the newest articles.'; public function collectData(){ - // Replaces all relative image URLs by absolute URLs. - // Relative URLs always start with 'local/'! - function replaceImageUrl($content){ - return preg_replace('/src=["\']{1}([^"\']+)/ims', 'src=\'' . self::URI . '$1\'', $content); - } - $html = getSimpleHTMLDOM(self::URI . 'spip.php?page=backend') or returnServerError('Could not request Bastamag.'); @@ -25,7 +19,13 @@ class BastaBridge extends BridgeAbstract { $item['title'] = $element->find('title', 0)->innertext; $item['uri'] = $element->find('guid', 0)->plaintext; $item['timestamp'] = strtotime($element->find('dc:date', 0)->plaintext); - $item['content'] = replaceImageUrl(getSimpleHTMLDOM($item['uri'])->find('div.texte', 0)->innertext); + // Replaces all relative image URLs by absolute URLs. + // Relative URLs always start with 'local/'! + $item['content'] = preg_replace( + '/src=["\']{1}([^"\']+)/ims', + 'src=\'' . self::URI . '$1\'', + getSimpleHTMLDOM($item['uri'])->find('div.texte', 0)->innertext + ); $this->items[] = $item; $limit++; } diff --git a/bridges/BingSearchBridge.php b/bridges/BingSearchBridge.php index eb8a5fc..357feb6 100644 --- a/bridges/BingSearchBridge.php +++ b/bridges/BingSearchBridge.php @@ -92,7 +92,7 @@ class BingSearchBridge extends BridgeAbstract or returnServerError('Could not request ' . self::NAME); $sizeKey = $this->getInput('image_size'); - $items = []; + $items = array(); foreach ($html->find('a.iusc') as $element) { $data = json_decode(htmlspecialchars_decode($element->getAttribute('m')), true); diff --git a/bridges/BloombergBridge.php b/bridges/BloombergBridge.php deleted file mode 100644 index 9eb1219..0000000 --- a/bridges/BloombergBridge.php +++ /dev/null @@ -1,69 +0,0 @@ -<?php -class BloombergBridge extends BridgeAbstract -{ - const NAME = 'Bloomberg'; - const URI = 'https://www.bloomberg.com/'; - const DESCRIPTION = 'Trending stories from Bloomberg'; - const MAINTAINER = 'mdemoss'; - - const PARAMETERS = array( - 'Trending Stories' => array(), - 'From Search' => array( - 'q' => array( - 'name' => 'Keyword', - 'required' => true - ) - ) - ); - - public function getName() - { - switch($this->queriedContext) { - case 'Trending Stories': - return self::NAME . ' Trending Stories'; - case 'From Search': - if (!is_null($this->getInput('q'))) { - return self::NAME . ' Search : ' . $this->getInput('q'); - } - break; - } - - return parent::getName(); - } - - public function getIcon() { - return 'https://assets.bwbx.io/s3/javelin/public/hub/images/favicon-black-63fe5249d3.png'; - } - - public function collectData() - { - switch($this->queriedContext) { - case 'Trending Stories': // Get list of top new <article>s from the front page. - $html = getSimpleHTMLDOMCached($this->getURI(), 300); - $stories = $html->find('ul.top-news-v3__stories article.top-news-v3-story'); - break; - case 'From Search': // Get list of <article> elements from search. - $html = getSimpleHTMLDOMCached( - $this->getURI() . - 'search?sort=time:desc&page=1&query=' . - urlencode($this->getInput('q')), 300 - ); - $stories = $html->find('div.search-result-items article.search-result-story'); - break; - } - foreach ($stories as $element) { - $item['uri'] = $element->find('h1 a', 0)->href; - if (preg_match('#^https://#i', $item['uri']) !== 1) { - $item['uri'] = $this->getURI() . $item['uri']; - } - $articleHtml = getSimpleHTMLDOMCached($item['uri']); - if (!$articleHtml) { - continue; - } - $item['title'] = $element->find('h1 a', 0)->plaintext; - $item['timestamp'] = strtotime($articleHtml->find('meta[name=iso-8601-publish-date],meta[name=date]', 0)->content); - $item['content'] = $articleHtml->find('meta[name=description]', 0)->content; - $this->items[] = $item; - } - } -} diff --git a/bridges/CNETFranceBridge.php b/bridges/CNETFranceBridge.php index 222c8b9..d005fd1 100644 --- a/bridges/CNETFranceBridge.php +++ b/bridges/CNETFranceBridge.php @@ -23,8 +23,8 @@ class CNETFranceBridge extends FeedExpander ) ); - private $bannedTitle = []; - private $bannedURL = []; + private $bannedTitle = array(); + private $bannedURL = array(); public function collectData() { diff --git a/bridges/CachetBridge.php b/bridges/CachetBridge.php index a60b8f7..75b1801 100644 --- a/bridges/CachetBridge.php +++ b/bridges/CachetBridge.php @@ -22,7 +22,7 @@ class CachetBridge extends BridgeAbstract { ); const CACHE_TIMEOUT = 300; - private $componentCache = []; + private $componentCache = array(); public function getURI() { return $this->getInput('host') === null ? 'https://cachethq.io/' : $this->getInput('host'); @@ -114,13 +114,13 @@ class CachetBridge extends BridgeAbstract { $uidOrig = $permalink . $incident->created_at; $uid = hash('sha512', $uidOrig); $timestamp = strtotime($incident->created_at); - $categories = []; + $categories = array(); $categories[] = $incident->human_status; if ($componentName !== '') { $categories[] = $componentName; } - $item = []; + $item = array(); $item['uri'] = $permalink; $item['title'] = $title; $item['timestamp'] = $timestamp; diff --git a/bridges/CastorusBridge.php b/bridges/CastorusBridge.php index c394283..fbd5007 100644 --- a/bridges/CastorusBridge.php +++ b/bridges/CastorusBridge.php @@ -2,7 +2,7 @@ class CastorusBridge extends BridgeAbstract { const MAINTAINER = 'logmanoriginal'; const NAME = 'Castorus Bridge'; - const URI = 'http://www.castorus.com'; + const URI = 'https://www.castorus.com'; const CACHE_TIMEOUT = 600; // 10min const DESCRIPTION = 'Returns the latest changes'; diff --git a/bridges/CollegeDeFranceBridge.php b/bridges/CollegeDeFranceBridge.php index 1f81683..9640c86 100644 --- a/bridges/CollegeDeFranceBridge.php +++ b/bridges/CollegeDeFranceBridge.php @@ -3,7 +3,7 @@ class CollegeDeFranceBridge extends BridgeAbstract { const MAINTAINER = 'pit-fgfjiudghdf'; const NAME = 'CollegeDeFrance'; - const URI = 'http://www.college-de-france.fr/'; + const URI = 'https://www.college-de-france.fr/'; const CACHE_TIMEOUT = 10800; // 3h const DESCRIPTION = 'Returns the latest audio and video from CollegeDeFrance'; diff --git a/bridges/ComicsKingdomBridge.php b/bridges/ComicsKingdomBridge.php new file mode 100644 index 0000000..b6228dc --- /dev/null +++ b/bridges/ComicsKingdomBridge.php @@ -0,0 +1,65 @@ +<?php +class ComicsKingdomBridge extends BridgeAbstract { + + const MAINTAINER = 'stjohnjohnson'; + const NAME = 'Comics Kingdom Unofficial RSS'; + const URI = 'https://www.comicskingdom.com/'; + const CACHE_TIMEOUT = 21600; // 6h + const DESCRIPTION = 'Comics Kingdom Unofficial RSS'; + const PARAMETERS = array( array( + 'comicname' => array( + 'name' => 'comicname', + 'type' => 'text', + 'required' => true + ) + )); + + public function collectData(){ + $html = getSimpleHTMLDOM($this->getURI(), array(), array(), true, false) + or returnServerError('Could not request Comics Kingdom: ' . $this->getURI()); + + // Get author from first page + $author = $html->find('div.author p', 0)->plaintext + or returnServerError('Comics Kingdom comic does not exist: ' . $this->getURI());; + + // Get current date/link + $link = $html->find('meta[property=og:url]', 0)->content; + for($i = 0; $i < 5; $i++) { + $item = array(); + + $page = getSimpleHTMLDOM($link) + or returnServerError('Could not request Comics Kingdom: ' . $link); + + $imagelink = $page->find('meta[property=og:image]', 0)->content; + $prevSlug = $page->find('slider-arrow[:is-left-arrow=true]', 0); + $link = $this->getURI() . '/' . $prevSlug->getAttribute('date-slug'); + + $date = explode('/', $link); + + $item['id'] = $imagelink; + $item['uri'] = $link; + $item['author'] = $author; + $item['title'] = 'Comics Kingdom ' . $this->getInput('comicname'); + $item['timestamp'] = DateTime::createFromFormat('Y-m-d', $date[count($date) - 1])->getTimestamp(); + $item['content'] = '<img src="' . $imagelink . '" />'; + + $this->items[] = $item; + } + } + + public function getURI(){ + if(!is_null($this->getInput('comicname'))) { + return self::URI . urlencode($this->getInput('comicname')); + } + + return parent::getURI(); + } + + public function getName(){ + if(!is_null($this->getInput('comicname'))) { + return $this->getInput('comicname') . ' - Comics Kingdom'; + } + + return parent::getName(); + } +} diff --git a/bridges/ContainerLinuxReleasesBridge.php b/bridges/ContainerLinuxReleasesBridge.php index d2f6325..d459b0f 100644 --- a/bridges/ContainerLinuxReleasesBridge.php +++ b/bridges/ContainerLinuxReleasesBridge.php @@ -10,20 +10,20 @@ class ContainerLinuxReleasesBridge extends BridgeAbstract { const BETA = 'beta'; const ALPHA = 'alpha'; - const PARAMETERS = [ - [ - 'channel' => [ + const PARAMETERS = array( + array( + 'channel' => array( 'name' => 'Release Channel', 'type' => 'list', 'defaultValue' => self::STABLE, - 'values' => [ + 'values' => array( 'Stable' => self::STABLE, 'Beta' => self::BETA, 'Alpha' => self::ALPHA, - ], - ] - ] - ]; + ), + ) + ) + ); private function getReleaseFeed($jsonUrl) { $json = getContents($jsonUrl) @@ -39,7 +39,7 @@ class ContainerLinuxReleasesBridge extends BridgeAbstract { $data = $this->getReleaseFeed($this->getJsonUri()); foreach ($data as $releaseVersion => $release) { - $item = []; + $item = array(); $item['uri'] = "https://coreos.com/releases/#$releaseVersion"; $item['title'] = $releaseVersion; diff --git a/bridges/DarkReadingBridge.php b/bridges/DarkReadingBridge.php new file mode 100644 index 0000000..3baaad7 --- /dev/null +++ b/bridges/DarkReadingBridge.php @@ -0,0 +1,79 @@ +<?php +class DarkReadingBridge extends FeedExpander { + const MAINTAINER = 'ORelio'; + const NAME = 'Dark Reading Bridge'; + const URI = 'https://www.darkreading.com/'; + const DESCRIPTION = 'Returns the newest articles from Dark Reading'; + + const PARAMETERS = array( array( + 'feed' => array( + 'name' => 'Feed', + 'type' => 'list', + 'values' => array( + 'All Dark Reading Stories' => '000_AllArticles', + 'Attacks/Breaches' => '644_Attacks/Breaches', + 'Application Security' => '645_Application%20Security', + 'Database Security' => '646_Database%20Security', + 'Cloud' => '647_Cloud', + 'Endpoint' => '648_Endpoint', + 'Authentication' => '649_Authentication', + 'Privacy' => '650_Privacy', + 'Mobile' => '651_Mobile', + 'Perimeter' => '652_Perimeter', + 'Risk' => '653_Risk', + 'Compliance' => '654_Compliance', + 'Operations' => '655_Operations', + 'Careers and People' => '656_Careers%20and%20People', + 'Identity and Access Management' => '657_Identity%20and%20Access%20Management', + 'Analytics' => '658_Analytics', + 'Threat Intelligence' => '659_Threat%20Intelligence', + 'Security Monitoring' => '660_Security%20Monitoring', + 'Vulnerabilities / Threats' => '661_Vulnerabilities%20/%20Threats', + 'Advanced Threats' => '662_Advanced%20Threats', + 'Insider Threats' => '663_Insider%20Threats', + 'Vulnerability Management' => '664_Vulnerability%20Management', + ) + ) + )); + + public function collectData(){ + $feed = $this->getInput('feed'); + $feed_splitted = explode('_', $feed); + $feed_id = $feed_splitted[0]; + $feed_name = $feed_splitted[1]; + if(empty($feed) || !ctype_digit($feed_id) || !preg_match('/[A-Za-z%20\/]/', $feed_name)) { + returnClientError('Invalid feed, please check the "feed" parameter.'); + } + $feed_url = $this->getURI() . 'rss_simple.asp'; + if ($feed_id != '000') { + $feed_url .= '?f_n=' . $feed_id . '&f_ln=' . $feed_name; + } + $this->collectExpandableDatas($feed_url); + } + + protected function parseItem($newsItem){ + $item = parent::parseItem($newsItem); + $article = getSimpleHTMLDOMCached($item['uri']) + or returnServerError('Could not request Dark Reading: ' . $item['uri']); + $item['content'] = $this->extractArticleContent($article); + $item['enclosures'] = array(); //remove author profile picture + return $item; + } + + private function extractArticleContent($article){ + $content = $article->find('div#article-main', 0)->innertext; + + foreach (array( + '<div class="divsplitter', + '<div style="float: left; margin-right: 2px;', + '<div class="more-insights', + '<div id="more-insights', + ) as $div_start) { + $content = stripRecursiveHTMLSection($content, 'div', $div_start); + } + + $content = stripWithDelimiters($content, '<h1 ', '</h1>'); + + return $content; + } +} diff --git a/bridges/DesoutterBridge.php b/bridges/DesoutterBridge.php index 0aae41a..38761ed 100644 --- a/bridges/DesoutterBridge.php +++ b/bridges/DesoutterBridge.php @@ -116,6 +116,12 @@ class DesoutterBridge extends BridgeAbstract { 'name' => 'Load full articles', 'type' => 'checkbox', 'title' => 'Enable to load the full article for each item' + ), + 'limit' => array( + 'name' => 'Limit', + 'type' => 'number', + 'defaultValue' => 3, + 'title' => "Maximum number of items to return in the feed.\n0 = unlimited" ) ) ); @@ -156,6 +162,8 @@ class DesoutterBridge extends BridgeAbstract { $this->title = html_entity_decode($html->find('title', 0)->plaintext, ENT_QUOTES); + $limit = $this->getInput('limit') ?: 0; + foreach($html->find('article') as $article) { $item = array(); @@ -169,6 +177,8 @@ class DesoutterBridge extends BridgeAbstract { } $this->items[] = $item; + + if ($limit > 0 && count($this->items) >= $limit) break; } } diff --git a/bridges/DiarioDoAlentejoBridge.php b/bridges/DiarioDoAlentejoBridge.php new file mode 100644 index 0000000..806f803 --- /dev/null +++ b/bridges/DiarioDoAlentejoBridge.php @@ -0,0 +1,60 @@ +<?php +class DiarioDoAlentejoBridge extends BridgeAbstract { + const MAINTAINER = 'somini'; + const NAME = 'Diário do Alentejo'; + const URI = 'https://www.diariodoalentejo.pt'; + const DESCRIPTION = 'Semanário Regionalista Independente'; + const CACHE_TIMEOUT = 28800; // 8h + + /* This is used to hack around obtaining a timestamp. It's just a list of Month names in Portuguese ... */ + const PT_MONTH_NAMES = array( + 'janeiro', + 'fevereiro', + 'março', + 'abril', + 'maio', + 'junho', + 'julho', + 'agosto', + 'setembro', + 'outubro', + 'novembro', + 'dezembro'); + + public function getIcon() { + return 'https://www.diariodoalentejo.pt/images/favicon/apple-touch-icon.png'; + } + + public function collectData(){ + /* This is slow as molasses (>30s!), keep the cache timeout high to avoid killing the host */ + $html = getSimpleHTMLDOMCached($this->getURI() . '/pt/noticias-listagem.aspx') + or returnServerError('Could not load content'); + + foreach($html->find('.list_news .item') as $element) { + $item = array(); + + $item_link = $element->find('.body h2.title a', 0); + /* Another broken URL, see also `bridges/ComboiosDePortugalBridge.php` */ + $item['uri'] = self::URI . implode('/', array_map('urlencode', explode('/', $item_link->href))); + $item['title'] = $item_link->innertext; + + $item['timestamp'] = str_ireplace( + array_map(function($name) { return ' ' . $name . ' '; }, self::PT_MONTH_NAMES), + array_map(function($num) { return sprintf('-%02d-', $num); }, range(1, sizeof(self::PT_MONTH_NAMES))), + $element->find('span.date', 0)->innertext); + + /* Fix the Image URL */ + $item_image = $element->find('img.thumb', 0); + $item_image->src = preg_replace('/.*&img=([^&]+).*/', '\1', $item_image->getAttribute('data-src')); + + /* Content: */ + /* - Image */ + /* - Category */ + $content = $item_image . + '<center>' . $element->find('a.category', 0) . '</center>'; + $item['content'] = defaultLinkTo($content, self::URI); + + $this->items[] = $item; + } + } +} diff --git a/bridges/DownDetectorBridge.php b/bridges/DownDetectorBridge.php new file mode 100644 index 0000000..4aef372 --- /dev/null +++ b/bridges/DownDetectorBridge.php @@ -0,0 +1,6195 @@ +<?php +class DownDetectorBridge extends BridgeAbstract { + + const MAINTAINER = 'teromene'; + const NAME = 'DownDetector Bridge'; + const URI = 'https://downdetector.com/'; + const DESCRIPTION = 'Returns most recent downtimes from DownDetector'; + const CACHE_TIMEOUT = 300; // 5 min + + const PARAMETERS = array( + 'All Websites' => array( + 'country' => array( + 'type' => 'list', + 'name' => 'Country', + 'values' => array( + 'Argentina' => 'https://downdetector.com.ar', + 'Australia' => 'https://downdetector.com.au', + 'België' => 'https://allestoringen.be', + 'Brasil' => 'https://downdetector.com.br', + 'Canada' => 'https://downdetector.ca', + 'Chile' => 'https://downdetector.cl', + 'Colombia' => 'https://downdetector.com.co', + 'Danmark' => 'https://downdetector.dk', + 'Deutschland' => 'https://allestörungen.de', + 'Ecuador' => 'https://downdetector.ec', + 'España' => 'https://downdetector.es', + 'France' => 'https://downdetector.fr', + 'Hong Kong' => 'https://downdetector.hk', + 'Hrvatska' => 'https://downdetector.hr', + 'India' => 'https://downdetector.in', + 'Indonesia' => 'https://downdetector.id', + 'Ireland' => 'https://downdetector.ie', + 'Italia' => 'https://downdetector.it', + 'Magyarország' => 'https://downdetector.hu', + 'Malaysia' => 'https://downdetector.my', + 'México' => 'https://downdetector.mx', + 'Nederland' => 'https://allestoringen.nl', + 'New Zealand' => 'https://downdetector.co.nz', + 'Norge' => 'https://downdetector.no', + 'Pakistan' => 'https://downdetector.pk', + 'Perú' => 'https://downdetector.pe', + 'Pilipinas' => 'https://downdetector.ph', + 'Polska' => 'https://downdetector.pl', + 'Portugal' => 'https://downdetector.pt', + 'România' => 'https://downdetector.ro', + 'Schweiz' => 'https://allestörungen.ch', + 'Singapore' => 'https://downdetector.sg', + 'Slovensko' => 'https://downdetector.sk', + 'South Africa' => 'https://downdetector.co.za', + 'Suomi' => 'https://downdetector.fi', + 'Sverige' => 'https://downdetector.se', + 'Türkiye' => 'https://downdetector.web.tr', + 'UAE' => 'https://downdetector.ae', + 'UK' => 'https://downdetector.co.uk', + 'United States' => 'https://downdetector.com', + 'Österreich' => 'https://allestörungen.at', + 'Česko' => 'https://downdetector.cz', + 'Ελλάς' => 'https://downdetector.gr', + 'Россия' => 'https://downdetector.ru', + '日本' => 'https://downdetector.jp' + ) + ) + ), + 'Specific Website' => array( + 'website' => array( + 'type' => 'list', + 'name' => 'Website', + 'values' => array( + 'Österreich' => array( + '1&1' => 35086, + '3 (Drei)' => 33546, + 'A1' => 33543, + 'Alexa' => 36919, + 'Amazon' => 33506, + 'Amazon Prime Video' => 35085, + 'Amino Apps' => 39034, + 'Anthem' => 38200, + 'Apex Legends' => 38117, + 'App Store' => 35584, + 'Bank Austria' => 34715, + 'Battlefield' => 38051, + 'BAWAG' => 34716, + 'Binance' => 36938, + 'Blizzard Battle.net' => 35087, + 'Bob' => 34953, + 'Boom Beach' => 34781, + 'Bwin' => 35071, + 'Call of Duty' => 34156, + 'Car2Go' => 34554, + 'Clash of Clans' => 35088, + 'Clash Royale' => 38357, + 'Coinbase' => 36804, + 'Counter-strike' => 35055, + 'Crunchyroll' => 38092, + 'Dazn' => 36508, + 'Dead By Daylight' => 37414, + 'Deezer' => 33832, + 'Destiny' => 34954, + 'DHL' => 36747, + 'Discord' => 36768, + 'Dota 2' => 35398, + 'Dropbox' => 33509, + 'EA' => 34502, + 'Easybank' => 36992, + 'eBay' => 33510, + 'Emerion' => 34613, + 'Epic Games Store' => 39021, + 'Erste Bank und Sparkasse' => 36724, + 'Facebook' => 33511, + 'Facebook Messenger' => 33512, + 'Fifa' => 37605, + 'Flickr' => 33513, + 'For Honor' => 35996, + 'Fortnite' => 36689, + 'Ghost Recon' => 36009, + 'Gmail' => 33514, + 'GMX' => 33515, + 'Google' => 33516, + 'Google Hangouts' => 33517, + 'Google Play' => 33518, + 'GTA 5' => 35082, + 'Guild Wars 2' => 36473, + 'Handy Parken' => 34316, + 'Hay Day' => 34854, + 'Hello Bank' => 37010, + 'HoT' => 38751, + 'iCloud' => 35501, + 'ICQ' => 33520, + 'ING DiBa' => 35129, + 'Instagram' => 33522, + 'iTunes' => 33523, + 'Kabelplus' => 34473, + 'Kik' => 33524, + 'Kraken' => 36770, + 'League of Legends' => 34350, + 'LinkedIn' => 33525, + 'Liwest' => 34471, + 'Lovoo' => 35079, + 'Magenta' => 38440, + 'Maxdome' => 35084, + 'Minecraft' => 36432, + 'Mittwald' => 36987, + 'N26' => 38834, + 'Netatmo' => 37956, + 'Netflix' => 34631, + 'Nintendo Network' => 35523, + 'Nitrado' => 35548, + 'NordVPN' => 38587, + 'Office 365' => 35120, + 'OneDrive' => 35412, + 'ORF' => 35600, + 'Origin' => 36889, + 'Outlook' => 35083, + 'Overwatch' => 36153, + 'Path of Exile' => 37730, + 'Paypal' => 35399, + 'Playerunknown\'s Battlegrounds' => 36488, + 'Playstation Network' => 33526, + 'Pokémon Go' => 35745, + 'Quizduell' => 34528, + 'Raiffeisen Bank' => 38750, + 'Rainbow Six' => 35563, + 'Red Dead Redemption' => 37739, + 'Reddit' => 36827, + 'Rocket League' => 35485, + 'roNET' => 37041, + 'Salzburg AG Cablelink' => 35601, + 'Shpock' => 38681, + 'Sky' => 35081, + 'Sky Ticket' => 35142, + 'Skype' => 33527, + 'Smart Hub' => 35400, + 'Snapchat' => 33528, + 'Spotify' => 33529, + 'Spusu' => 35598, + 'Steam' => 34117, + 'Teamviewer' => 35686, + 'Tele2' => 34339, + 'Telegram' => 34903, + 'Telering' => 34952, + 'The Division' => 35599, + 'The elder scrolls online' => 37160, + 'The Simpsons Tapped Out' => 37283, + 'Threema' => 34255, + 'Tinder' => 34243, + 'Tipico' => 36515, + 'Tumblr' => 33530, + 'Twitch' => 35024, + 'Twitter' => 33531, + 'Uplay PC' => 34689, + 'Viber' => 33532, + 'Viewster' => 34326, + 'Vimeo' => 33533, + 'Volksbank' => 34717, + 'Warface' => 37524, + 'Warframe' => 37136, + 'Waze' => 33534, + 'Whatsapp' => 33535, + 'Wikipedia' => 33536, + 'Willhaben.at' => 35859, + 'World of Tanks' => 36674, + 'World of Warcraft' => 36998, + 'World of Warships' => 38009, + 'Xbox Live' => 33538, + 'Yahoo Mail' => 33539, + 'Yahoo Messenger' => 33540, + 'Yesss' => 35346, + 'Youtube' => 33541, + 'Z1 Battle Royale' => 35489, + ), + 'Deutschland' => array( + '1&1' => 32554, + '1blu' => 37319, + '2k' => 37731, + '3CX' => 36439, + '3sat' => 35797, + 'Afterbuy' => 37015, + 'Airbnb' => 35422, + 'Albion Online' => 38799, + 'Aldi Talk' => 32579, + 'Alexa' => 35912, + 'All-inkl' => 35162, + 'Amazon' => 32572, + 'Amazon Prime Music' => 37584, + 'Amazon Prime Video' => 34495, + 'Amazon Web Services' => 36326, + 'Amino Apps' => 39033, + 'Amplus' => 35446, + 'Anthem' => 38055, + 'Anydesk' => 37487, + 'AOL' => 34377, + 'Apex Legends' => 38112, + 'App Store' => 35579, + 'Apple Music' => 35246, + 'Apple Store' => 34448, + 'Arche NetVision' => 35593, + 'ArcheAge' => 35062, + 'Arcor' => 34374, + 'ARK: Survival Evolved' => 39065, + 'Arma 3' => 35063, + 'Asana' => 38024, + 'Assassin\'s Creed' => 35010, + 'Badoo' => 35011, + 'Base' => 32568, + 'Battlefield' => 36092, + 'Baur' => 35043, + 'Bet3000' => 35035, + 'Bet365' => 35034, + 'Bethesda' => 38317, + 'BILDmobil' => 32609, + 'Binance' => 36942, + 'Bing' => 34708, + 'Bitfinex' => 36833, + 'Bitstamp' => 36808, + 'Blackberry' => 3, + 'Blade &Soul' => 35512, + 'Blau' => 37655, + 'Blau' => 34108, + 'Blizzard Battle.net' => 34483, + 'Blogger' => 32606, + 'BMW ConnectedDrive' => 38034, + 'Boom Beach' => 34365, + 'Bornet' => 34944, + 'Bwin' => 34491, + 'Call of Duty' => 34155, + 'Candy Crush' => 35148, + 'Candy Crush Soda Saga' => 35174, + 'Car-Net' => 37031, + 'Car2Go' => 34555, + 'Centurylink' => 35624, + 'Checkdomain' => 36096, + 'Clash of Clans' => 34289, + 'Clash Royale' => 35588, + 'Cloudflare' => 34881, + 'Coinbase' => 36798, + 'Colt' => 37653, + 'Comdirect' => 34774, + 'Comedy Central' => 34122, + 'Commerzbank' => 32607, + 'Comunio' => 34719, + 'Congstar' => 32590, + 'Consors Bank' => 35545, + 'CosmosDirect' => 35042, + 'Counter-strike' => 34887, + 'Crunchyroll' => 36718, + 'DABbank' => 35921, + 'Das Erste' => 34386, + 'Dazn' => 35956, + 'Dead By Daylight' => 35951, + 'Deezer' => 33831, + 'DeGiro' => 38203, + 'Deliveroo' => 37546, + 'Destiny' => 34895, + 'Deutsche Bahn' => 32569, + 'Deutsche Bank' => 32611, + 'Deutsche Glasfaser' => 36087, + 'Deutsche Telefon' => 35851, + 'DeutschlandSIM' => 34635, + 'DFP' => 35004, + 'DHL' => 34896, + 'Discord' => 35796, + 'DKB' => 32767, + 'DNSNET' => 35670, + 'DomainFactory' => 37381, + 'Dota 2' => 34900, + 'dpd' => 36120, + 'Dragon Ball' => 36380, + 'Drillisch' => 36019, + 'Driveclub' => 34928, + 'Dropbox' => 32585, + 'E-Plus' => 10121, + 'EA' => 34497, + 'Easybell' => 34370, + 'eBay' => 32567, + 'Ecotel' => 36794, + 'Elite: Dangerous' => 37077, + 'Emailn' => 34687, + 'Emerion' => 34614, + 'Entega' => 37039, + 'Epic Games Store' => 38827, + 'Escape from Tarkov' => 37977, + 'Etoro' => 36965, + 'Eurosport Player' => 36559, + 'Eventim' => 37621, + 'Evernote ' => 36506, + 'Ewe TEL' => 33559, + 'Facebook' => 32552, + 'Facebook Messenger' => 32560, + 'Faceit' => 37147, + 'Facetime' => 34603, + 'Fallout' => 35433, + 'Farm Heroes Saga' => 35175, + 'Fidor Bank' => 35894, + 'Fifa' => 35469, + 'Finya' => 37060, + 'Fitbit' => 37972, + 'Fl!nk' => 35170, + 'Flickr' => 32604, + 'Fonic' => 32594, + 'For Honor' => 35985, + 'Fortnite' => 36626, + 'Forza' => 37568, + 'Freenet' => 34354, + 'Friday the 13th The Game' => 37561, + 'Fyve' => 34378, + 'G-Portal' => 37155, + 'Game of war' => 35230, + 'Gameduell' => 37566, + 'Gardena Smart' => 37350, + 'Garmin' => 37049, + 'Gears of War' => 35940, + 'Gems of war' => 38802, + 'Geocaching' => 37178, + 'Ghost Recon' => 36001, + 'Giropay' => 38204, + 'GitHub' => 35348, + 'GLS' => 36119, + 'Gmail' => 32584, + 'GMX' => 32563, + 'Go Daddy' => 34874, + 'Goneo' => 37576, + 'Google' => 32553, + 'Google Drive' => 36603, + 'Google Hangouts' => 32600, + 'Google Kalender' => 38603, + 'Google Play' => 32593, + 'Gran Turismo' => 36917, + 'Grindr' => 35532, + 'GTA 5' => 34754, + 'Guild Wars 2' => 35061, + 'Halo' => 35419, + 'Halo Wars' => 36034, + 'Harry Potter: Wizards Unite' => 38686, + 'Hay Day' => 34366, + 'Helinet' => 34959, + 'Hermes' => 35196, + 'Hetzner ' => 35943, + 'Hipchat' => 34869, + 'Hitbox.TV' => 35932, + 'Hitman' => 35586, + 'Homematic' => 36795, + 'Hosteurope' => 37958, + 'Htp' => 34400, + 'Hue' => 37810, + 'Hunt: Showdown' => 38787, + 'HypoVereinsbank' => 34965, + 'iCloud' => 32549, + 'ICQ' => 33123, + 'Idealo' => 37156, + 'iMessage' => 32671, + 'Inexio' => 36371, + 'ING DiBa' => 35156, + 'Ingress' => 35765, + 'Innogy Highspeed' => 37459, + 'Instagram' => 32599, + 'Intercity Express (ICE)' => 32581, + 'iTunes' => 32672, + 'Jappy' => 32596, + 'Jira' => 36066, + 'Jobst DSL' => 36727, + 'Jodel' => 36793, + 'Joyn' => 38604, + 'Jurassic World Alive' => 37310, + 'K-Classic Mobil' => 33986, + 'Kabel eins' => 34392, + 'Kickbase' => 37451, + 'Kicker' => 37450, + 'Kicktipp' => 35824, + 'Kik' => 33353, + 'Klarmobil' => 32605, + 'KMS' => 34399, + 'Knuddels' => 35865, + 'Kraken' => 36749, + 'Ladbrokes' => 35161, + 'LastPass' => 34780, + 'League of Legends' => 34112, + 'Lebara' => 35791, + 'Line' => 34300, + 'LinkedIn' => 32557, + 'Lotto24' => 35040, + 'Lottohelden' => 36882, + 'Lovoo' => 34814, + 'Lufthansa' => 32574, + 'Lycamobile' => 34939, + 'M-net' => 32571, + 'Madden' => 38906, + 'Mail.de' => 34909, + 'Mailbox' => 34832, + 'Markt.de' => 37465, + 'Maxdome' => 34749, + 'MDCC' => 34760, + 'MDDSL' => 37056, + 'Mercedes Me' => 37153, + 'MiCoach' => 34936, + 'Microsoft Azure' => 36093, + 'Microsoft Teams' => 38185, + 'Minecraft' => 32556, + 'Mittwald' => 33412, + 'Mixer' => 38770, + 'Mobilcom Debitel' => 32610, + 'MTV' => 34120, + 'My Fitness Pal' => 37637, + 'Mybet' => 35036, + 'N26' => 35719, + 'NBA 2k' => 38595, + 'Need for Speed' => 35429, + 'Netatmo' => 37452, + 'Netbeat' => 35906, + 'NetCologne' => 32587, + 'netcombw' => 35638, + 'netcup' => 35632, + 'Netflix' => 34630, + 'Netkom' => 37201, + 'Neverwinter' => 35768, + 'Nfon' => 35792, + 'Nintendo Network' => 35519, + 'Nintendo Switch Online' => 37244, + 'Nitrado' => 34941, + 'No Man\'s Sky' => 35794, + 'NordVPN' => 38584, + 'Norisbank' => 34964, + 'Nvidia' => 37462, + 'Nvidia' => 39069, + 'O2' => 10122, + 'Office 365' => 34730, + 'OkCupid' => 37330, + 'OLB' => 37057, + 'OneDrive' => 35408, + 'Onleihe' => 35635, + 'Origin' => 34371, + 'Osnatel' => 33873, + 'Otelo' => 35480, + 'Otto' => 32598, + 'Outlook' => 32546, + 'Overwatch' => 35684, + 'Paladins' => 35925, + 'Path of Exile' => 36479, + 'Payback' => 37654, + 'Paypal' => 34375, + 'pcvisit' => 37643, + 'PES' => 37952, + 'Pet Rescue Saga' => 35176, + 'Pinterest' => 37585, + 'Placetel' => 35128, + 'Playerunknown\'s Battlegrounds' => 36332, + 'Playstation Network' => 32551, + 'Pokémon Duel' => 35976, + 'Pokémon Go' => 35724, + 'Pokerstars' => 37439, + 'Postbank' => 32589, + 'Posteo' => 34309, + 'Primacom' => 33502, + 'ProSieben' => 34390, + 'PŸUR' => 32592, + 'QSC' => 33560, + 'Quizduell' => 34292, + 'Rainbow Six' => 35479, + 'Razer' => 38699, + 'Realm Royale' => 37288, + 'Red Dead Redemption' => 37601, + 'Reddit' => 35882, + 'RFT Kabel' => 35831, + 'Roblox' => 35815, + 'Rocket League' => 35252, + 'Royal Games' => 38217, + 'RTL II' => 34393, + 'RTL Television' => 34387, + 'Runescape' => 35108, + 'RWE' => 36116, + 'RWW' => 37955, + 'Ryanair' => 37518, + 'Salesforce' => 34733, + 'Santander Consumer Bank' => 32603, + 'Sat.1' => 34389, + 'Save.TV' => 37193, + 'Sea of Thieves' => 37112, + 'Shpock' => 37311, + 'Signal' => 37072, + 'Simply' => 36376, + 'Simquadrat' => 34945, + 'Simsme' => 34795, + 'Simyo' => 32591, + 'Sipgate' => 34127, + 'SKL' => 35041, + 'Sky' => 32562, + 'Sky Ticket' => 35141, + 'Skype' => 32561, + 'Skype for Business' => 35351, + 'Slack' => 35936, + 'Smart Hub' => 35181, + 'Smite' => 34803, + 'Snapchat' => 33377, + 'Soundcloud' => 34353, + 'Sparda' => 35370, + 'Sparkasse' => 32757, + 'Speedtest' => 38780, + 'Spiegel' => 36050, + 'Spotify' => 32564, + 'Star Citizen' => 39035, + 'Star Wars Battlefront' => 35460, + 'Steam' => 32559, + 'Strato' => 33413, + 'Strava' => 38731, + 'Streetspotr' => 34920, + 'Summoners War' => 37420, + 'SWB' => 34515, + 'Tado' => 36634, + 'Tango' => 33731, + 'Targobank' => 34966, + 'Teamspeak' => 33346, + 'Teamviewer' => 34344, + 'Tele2' => 33503, + 'Tele5' => 35727, + 'Telegram' => 34229, + 'Telekom' => 10117, + 'Tellonym' => 37248, + 'The Crew 2' => 37252, + 'The Division' => 35570, + 'The elder scrolls online' => 34480, + 'The Simpsons Tapped Out' => 34701, + 'Threema' => 34253, + 'Tiktok' => 39044, + 'Tinder' => 34242, + 'Tipico' => 34714, + 'TNG' => 38772, + 'Todoist' => 36462, + 'TomTom' => 35813, + 'Tumblr' => 32588, + 'TuneIn' => 38763, + 'TV Now' => 35143, + 'Tweakbox' => 38349, + 'Twitch' => 34376, + 'Twitter' => 32583, + 'Udemy' => 38388, + 'Unitymedia' => 32548, + 'Uplay PC' => 34380, + 'Usenext' => 36117, + 'Vero' => 37064, + 'Versatel' => 33561, + 'Viber' => 33372, + 'Viewster' => 34324, + 'Vimeo' => 32582, + 'Visa' => 37238, + 'VIVA' => 34121, + 'Vodafone' => 10120, + 'Volksbanken und Raiffeisenbanken' => 32758, + 'VOX' => 34391, + 'Warface' => 35944, + 'Warframe' => 36366, + 'Watchbox' => 36537, + 'Wattpad' => 34700, + 'Waze' => 33411, + 'Web.de' => 32586, + 'WeChat' => 34301, + 'Weebly' => 34914, + 'Weight Watchers' => 35662, + 'WeTransfer' => 36433, + 'Wetter.com' => 36051, + 'WetterOnline' => 34810, + 'Whatsapp' => 32555, + 'Wikipedia' => 32565, + 'Wilhelm.tel' => 34398, + 'Wish' => 38153, + 'WiSoTEL' => 37543, + 'Wobcom' => 35991, + 'Wordpress' => 32570, + 'World of Tanks' => 35524, + 'World of Warcraft' => 34373, + 'World of Warships' => 36638, + 'Wüstenrot' => 36977, + 'Xbox Live' => 32573, + 'Xing' => 34822, + 'Yahoo Mail' => 32597, + 'Yahoo Messenger' => 32580, + 'Yourfone' => 33415, + 'Youtube' => 32578, + 'Youtube Music' => 37586, + 'Z1 Battle Royale' => 35147, + 'Zattoo' => 35367, + 'ZDF' => 34388, + 'Zynga' => 32608, + ), + 'Nederland' => array( + '112' => 10011, + '3FM' => 10174, + '9292.nl' => 33376, + 'ABN-Amro' => 29, + 'ABP pensioenfonds' => 35862, + 'Adobe Creative Cloud' => 34916, + 'ADP' => 32669, + 'Adyen' => 37610, + 'Aegon Bank' => 10132, + 'Afas' => 10093, + 'Afterpay' => 34769, + 'Airbnb' => 35423, + 'Airmiles' => 37516, + 'Albert Heijn' => 34010, + 'Alex' => 10056, + 'Algemeen Dagblad' => 1, + 'AliExpress' => 37384, + 'Amazon' => 37379, + 'Amazon Prime Video' => 36976, + 'AMSIX' => 10008, + 'Antagonist' => 35160, + 'Anthem' => 38054, + 'Apex Legends' => 38118, + 'App Store' => 35580, + 'Apple Music' => 35245, + 'Apple Store' => 34446, + 'Argenta' => 10158, + 'Argeweb' => 35073, + 'Arriva' => 2, + 'ASN Bank' => 10048, + 'Assassin\'s Creed' => 35009, + 'Badoo' => 37650, + 'Battlefield' => 37094, + 'Belastingdienst' => 10002, + 'Ben' => 10053, + 'Bibliotheek' => 34132, + 'Binance' => 36879, + 'Binck' => 10055, + 'Bing' => 34707, + 'BlaBlaCar' => 36088, + 'Bliep' => 33998, + 'Blizzard Battle.net' => 34485, + 'Bol.com' => 10112, + 'Booking.com' => 37574, + 'Boom Beach' => 34363, + 'Brabant Water' => 10071, + 'Brawl Stars' => 38818, + 'Budgetphone' => 35132, + 'Buienalarm' => 37245, + 'Buienradar' => 33565, + 'Bunq' => 35820, + 'Byte' => 32764, + 'Caiway' => 4, + 'CAK' => 37289, + 'Call of Duty' => 34154, + 'CanalDigitaal' => 31, + 'Candy Crush' => 34025, + 'Cbizz' => 37659, + 'Centraal Beheer Achmea' => 10157, + 'Centraal Bureau voor de Statistiek' => 10168, + 'CheapConnect' => 36122, + 'Chelloo' => 35546, + 'Choozze' => 35096, + 'Clash of Clans' => 34290, + 'Clash Royale' => 37522, + 'Cloudflare' => 38623, + 'Cloudhosting.nl' => 33486, + 'Coinbase' => 36236, + 'Comedy Central' => 34033, + 'Concepts' => 10043, + 'Connexxion' => 5, + 'Coolblue' => 35543, + 'Counter-strike' => 36644, + 'Credit Europe Bank' => 10194, + 'Crunchyroll' => 36722, + 'Dead By Daylight' => 37412, + 'Deezer' => 33769, + 'DeGiro' => 34019, + 'Delight Mobile' => 33987, + 'Delta' => 10123, + 'Destiny' => 34891, + 'Deutsche Bank' => 10119, + 'DFP' => 35003, + 'DHL' => 35223, + 'DigiD' => 10001, + 'Digipoort' => 34520, + 'Discord' => 36043, + 'Disney+' => 38319, + 'Dota 2' => 36397, + 'Dpd' => 35619, + 'Dropbox' => 10192, + 'Dumpert' => 33375, + 'Dunea' => 10074, + 'EA' => 34501, + 'Easynet' => 33997, + 'eBay' => 33857, + 'Elite: Dangerous' => 37777, + 'Enduris' => 35999, + 'Eneco' => 10124, + 'Energielabel voor Woningen' => 35117, + 'Enexis' => 10014, + 'Ennatuurlijk' => 35159, + 'Epic Games Store' => 39020, + 'Escape from Tarkov' => 39059, + 'Esprit Telecom' => 10150, + 'Essent' => 10114, + 'Etoro' => 36958, + 'Eurosport Player' => 35821, + 'Eventim' => 37622, + 'Evides' => 10072, + 'Eweka' => 10039, + 'Exact Online' => 34815, + 'Exchange Online' => 34728, + 'Facebook' => 6, + 'Facebook Messenger' => 10185, + 'Facetime' => 34607, + 'Fallout' => 35434, + 'FBTO' => 34015, + 'Feedly' => 34712, + 'Fiber' => 10103, + 'Fifa' => 35474, + 'Flickr' => 37948, + 'Flitsmeister' => 34369, + 'For Honor' => 35987, + 'Fortnite' => 36625, + 'Fox Sports' => 10096, + 'Friday the 13th The Game' => 37560, + 'Funda' => 32576, + 'Game of war' => 35231, + 'Garmin' => 38165, + 'Garmin Connect' => 38171, + 'Gatehub' => 36957, + 'Ghost Recon' => 36010, + 'GitHub' => 35347, + 'Glashart Media' => 10105, + 'GLS' => 36118, + 'Gmail' => 10041, + 'Google' => 10010, + 'Google Agenda' => 38602, + 'Google Drive' => 34276, + 'Google Hangouts' => 10062, + 'Google Play' => 10038, + 'Gran Turismo' => 36873, + 'Greenchoice' => 37959, + 'Greenwheels' => 34007, + 'Grindr' => 35531, + 'GTA 5' => 34753, + 'Guild Wars 2' => 36464, + 'GVB' => 7, + 'Halo' => 35420, + 'Happn' => 37014, + 'Harry Potter: Wizards Unite' => 38689, + 'Hay Day' => 34368, + 'Hearthstone' => 38564, + 'Hollandsnieuwe' => 10040, + 'Hosted.nl' => 33483, + 'Hostnet' => 32761, + 'HTM' => 8, + 'Hue' => 37812, + 'iCloud' => 30, + 'iDeal' => 10025, + 'IEX' => 35782, + 'IG' => 34307, + 'iMessage' => 10130, + 'Indeed' => 35941, + 'Infopact' => 37565, + 'ING' => 9, + 'Instagram' => 32558, + 'International Card Services (ICS)' => 10169, + 'InterNLnet' => 34252, + 'Interpolis' => 34017, + 'ITDev Solutions' => 35533, + 'iTunes' => 10151, + 'Jira' => 36067, + 'Jonaz' => 37348, + 'Jumbo' => 36184, + 'Jurassic World Alive' => 37334, + 'JustEat' => 10164, + 'Kabel Noord' => 10113, + 'Kabeltex' => 10138, + 'Kadaster' => 37652, + 'Kamer van Koophandel' => 10167, + 'KickXL' => 10098, + 'Kik' => 10191, + 'Kliksafe' => 10109, + 'KLM' => 10028, + 'Knab' => 10131, + 'KNMI' => 34013, + 'KPN' => 11, + 'Kraken' => 36748, + 'Kruidvat' => 37312, + 'LastPass' => 34779, + 'League of Legends' => 35169, + 'LeasePlan Bank' => 10160, + 'Leaseweb' => 32762, + 'Lebara' => 10128, + 'Lexa.nl' => 35838, + 'Liander' => 10013, + 'Lijbrandt' => 10045, + 'LinkedIn' => 10201, + 'Litebit' => 36836, + 'Lloyds Bank' => 10154, + 'LOI' => 34947, + 'Lotto' => 34923, + 'Lycamobile' => 10129, + 'Lynx' => 10085, + 'Magister' => 35274, + 'Marktplaats' => 10170, + 'Microsoft Azure' => 36114, + 'Microsoft Teams' => 38186, + 'Mijnbroker' => 10088, + 'Mijndomein' => 34348, + 'MijnOverheid' => 10015, + 'Minecraft' => 36173, + 'Mobicross' => 34898, + 'Moneyou' => 10155, + 'Motto' => 35482, + 'MTV' => 34031, + 'Multisafepay' => 34877, + 'My Fitness Pal' => 37636, + 'MyOrder' => 34291, + 'Nationale Nederlanden' => 10166, + 'Nest' => 35189, + 'Net 5' => 10181, + 'Netatmo' => 37453, + 'Netflix' => 33849, + 'Neverwinter' => 36676, + 'NIBC Direct' => 10159, + 'Nintendo eShop' => 34105, + 'Nintendo Network' => 35520, + 'Nintendo Switch Online' => 37242, + 'Nitrado' => 35549, + 'NLE' => 37651, + 'NLziet' => 34219, + 'NordVPN' => 38585, + 'NOS.nl' => 10063, + 'NPO 1' => 10179, + 'NPO 2' => 10180, + 'NPO 3' => 10182, + 'NPO Start' => 10064, + 'NS' => 21, + 'Nu.nl' => 12, + 'Nuon' => 10084, + 'Oasen' => 10078, + 'Office 365' => 35119, + 'OHRA' => 34819, + 'ON' => 10097, + 'OneDrive' => 32779, + 'Online.nl' => 10193, + 'OnlineWerkplekken.nl' => 33485, + 'Onsbrabantnet' => 10044, + 'Origin' => 34372, + 'Outlook' => 10042, + 'OV-chipkaart' => 10145, + 'Overwatch' => 35723, + 'Paladins' => 37407, + 'Park Mobile' => 10139, + 'Park-line' => 10137, + 'Path of Exile' => 37729, + 'Pathé Thuis' => 33848, + 'Paypal' => 10021, + 'Paysafecard' => 10152, + 'PCextreme' => 32763, + 'Picnic' => 37503, + 'PIN' => 10009, + 'Player Unknown\'s Battlegrounds' => 36336, + 'Playstation Network' => 10006, + 'Plinq' => 10108, + 'Pokémon Go' => 35731, + 'Pokerstars' => 37438, + 'PostNL' => 32766, + 'PWN Waterleidingbedrijf Noord-Holland' => 10073, + 'Q-Park' => 10111, + 'Quizduel' => 34293, + 'Qurrent' => 35729, + 'Rabobank' => 13, + 'Radio 1' => 10175, + 'Radio 2' => 10176, + 'Raet' => 32670, + 'Rainbow Six' => 35564, + 'Realm Royale' => 37315, + 'Red Dead Redemption' => 38286, + 'Reddit' => 36822, + 'Redworks' => 34773, + 'Reggefiber' => 10104, + 'RegioBank' => 10050, + 'Rekam' => 10195, + 'Rendo Netwerken' => 10126, + 'RET' => 14, + 'Reviced' => 36061, + 'Robeco' => 10153, + 'Robin Mobile' => 35695, + 'Roblox' => 35814, + 'Rocket League' => 35254, + 'RoutIT' => 34349, + 'RTL 5' => 10183, + 'RTL 8' => 10184, + 'RTL XL' => 10066, + 'RTL4' => 10178, + 'Runescape' => 35701, + 'Ruzzle' => 33968, + 'Ryanair' => 37517, + 'Salesforce' => 10016, + 'SBS6' => 10177, + 'Schiphol' => 10027, + 'Scorito' => 34726, + 'Sea of Thieves' => 37113, + 'SEOshop' => 35592, + 'Sharepoint Online' => 34732, + 'Signal' => 37073, + 'Signet' => 34407, + 'Simpel' => 10037, + 'Simyo' => 10054, + 'Skype' => 10024, + 'Skype for Business' => 34729, + 'Slack' => 37336, + 'Smart Hub' => 35180, + 'Snapchat' => 10187, + 'Snappet' => 37613, + 'SNS' => 10019, + 'Sociale Verzekeringsbank (SVB)' => 10186, + 'Sofort Banking' => 10149, + 'Solcon' => 10099, + 'Soundcloud' => 34352, + 'Sparql' => 34519, + 'Speurders' => 34805, + 'Spotify' => 10003, + 'Staatsloterij' => 10094, + 'Star Wars Battlefront' => 36918, + 'Steam' => 34106, + 'Stedin' => 10012, + 'Steep' => 37823, + 'Stemwijzer' => 35980, + 'Stichting Kabeltelevisie Pijnacker' => 34143, + 'Stipte' => 10102, + 'Strato' => 35045, + 'Strava' => 36046, + 'Studiemeter' => 37075, + 'Studystore' => 36600, + 'Surfnet' => 34396, + 'T-Mobile' => 19, + 'Tado' => 36633, + 'Tango' => 33740, + 'Teamviewer' => 34342, + 'Tele2' => 16, + 'Telegraaf' => 17, + 'Telegram' => 34221, + 'Telfort' => 18, + 'The Division' => 35569, + 'The elder scrolls online' => 37329, + 'Threema' => 34254, + 'Thuisbezorgd.nl' => 10163, + 'Ticketmaster' => 10133, + 'Tickney ' => 35923, + 'Tikkie' => 36737, + 'Tiktok' => 39074, + 'Tinder' => 34238, + 'Today\'s' => 10087, + 'TomTom Live' => 34917, + 'Toto' => 35590, + 'TradersOnly' => 10090, + 'Transavia' => 35168, + 'TransIP' => 32771, + 'Trined' => 10107, + 'Triodos Bank' => 10051, + 'True' => 36576, + 'Tumblr' => 36714, + 'TuneIn' => 38762, + 'Tweak' => 10100, + 'Tweakbox' => 38348, + 'Tweakers' => 37376, + 'Twinfield' => 36725, + 'Twitch' => 35025, + 'Twitter' => 22, + 'Unet' => 34408, + 'Uplay PC' => 34379, + 'UWV en Werk.nl' => 10017, + 'Van Lanschot Bankiers' => 10052, + 'VDX' => 35780, + 'Vectone' => 35237, + 'Veolia' => 32612, + 'Veronica' => 34493, + 'Versio' => 32765, + 'VGZ' => 34946, + 'Viber' => 10172, + 'Videoland' => 33850, + 'Vimeo' => 38534, + 'Vimexx' => 35924, + 'VirtualComputing.nl' => 35698, + 'Vitens' => 10070, + 'Vodafone' => 24, + 'VoIPmobiel' => 34692, + 'Volgjezorg' => 37645, + 'VPSHosting.nl' => 33487, + 'VPSServer.nl' => 33484, + 'VVV Cadeaubon' => 35134, + 'Warface' => 38764, + 'Warframe' => 36490, + 'Waterbedrijf Groningen' => 10077, + 'Waterleiding Maatschappij Limburg' => 10076, + 'Waterleidingmaatschappij Drenthe' => 10079, + 'Waternet' => 10075, + 'Waze' => 33409, + 'Webex' => 34164, + 'Webreus' => 32778, + 'Weebly' => 34913, + 'Weeronline.nl' => 34014, + 'Weerplaza' => 35115, + 'Wehkamp' => 33980, + 'Westland Infra' => 10125, + 'WeTransfer' => 10190, + 'Whatsapp' => 10000, + 'Wikipedia' => 10092, + 'Wish' => 38152, + 'Wisper' => 10101, + 'Woningnet' => 36758, + 'Wordfeud' => 25, + 'WordOn' => 34036, + 'World of Tanks' => 35526, + 'World of Warcraft' => 34382, + 'World of Warships' => 38010, + 'Wrts' => 34215, + 'Xbox Live' => 10148, + 'XS4ALL' => 26, + 'XSyou' => 10106, + 'Yahoo Mail' => 34020, + 'Yellowbrick' => 10140, + 'Youfone' => 10144, + 'Yourhosting' => 34360, + 'YouTube' => 10005, + 'Z1 Battle Royale' => 35495, + 'Zalando' => 33981, + 'Ziggo' => 28, + 'Zilveren Kruis' => 34727, + 'Zwitserleven' => 34262, + ), + 'UK' => array( + '123 Reg' => 35870, + '1and1' => 34818, + '2k' => 36427, + '3 (Three)' => 32674, + '4chan' => 38596, + 'Abebooks' => 36536, + 'Adobe Creative Cloud' => 34552, + 'Airbnb' => 35424, + 'Alexa' => 35911, + 'AliExpress' => 39062, + 'Amazon' => 32613, + 'Amazon Prime Music' => 36426, + 'Amazon Prime Video' => 34494, + 'Amazon Web Services' => 36327, + 'American Express' => 37398, + 'Amino Apps' => 38196, + 'Ancestry' => 38680, + 'Anthem' => 38053, + 'Anydesk' => 37489, + 'Apex Legends' => 38114, + 'App Store' => 35578, + 'Apple Music' => 35242, + 'Apple Store' => 34454, + 'Argos' => 34018, + 'ARK: Survival Evolved' => 36551, + 'Arlo' => 37076, + 'Asana' => 38023, + 'Asda' => 37979, + 'Ask4' => 34411, + 'Assassin\'s Creed' => 35006, + 'Autotrader' => 34793, + 'Badoo' => 37501, + 'Bank of Ireland UK' => 38228, + 'Bank of Scotland' => 32692, + 'Barclaycard' => 37762, + 'Barclays' => 32685, + 'Battlefield' => 36585, + 'Bet365' => 35030, + 'Betfair' => 35031, + 'Binance' => 36877, + 'Bing' => 33615, + 'Bitbucket' => 36683, + 'Black Desert Online' => 38492, + 'Blizzard Battle.net' => 34487, + 'Blogger' => 32617, + 'Booking.com' => 38703, + 'Boom Beach' => 34783, + 'Brawl Stars' => 38819, + 'British Airways' => 37644, + 'British Gas' => 35653, + 'BT' => 32673, + 'Bumble' => 36401, + 'Bwin' => 34490, + 'Cablecom' => 34413, + 'Cahoot' => 34826, + 'Call of Duty' => 34151, + 'Candy Crush' => 35094, + 'Capital One' => 37223, + 'Car-Net' => 37030, + 'Cdkeys' => 37575, + 'Centurylink' => 35625, + 'CEX' => 34897, + 'Channel 4' => 34948, + 'Chelsea Building Society' => 38223, + 'Clash of Clans' => 34444, + 'Clash Royale' => 36856, + 'Cloudflare' => 34880, + 'CMC Markets' => 37629, + 'Coinbase' => 36797, + 'Colt Group ' => 35961, + 'Conan Exiles' => 38392, + 'ConnectWise' => 38469, + 'Conventry Building Society' => 38225, + 'Counter-strike' => 35057, + 'Craigslist' => 32619, + 'Crunchyroll' => 36715, + 'Daisy' => 34410, + 'Danske Bank' => 38227, + 'Dark Souls' => 36953, + 'Dauntless' => 38541, + 'DayZ' => 38781, + 'Dazn' => 39010, + 'Dead By Daylight' => 36425, + 'Deezer' => 33829, + 'DeGiro' => 38202, + 'Deliveroo' => 37548, + 'Demon' => 34412, + 'Destiny' => 34893, + 'DeviantArt' => 38491, + 'DFP' => 34999, + 'Discord' => 36020, + 'Dota 2' => 35403, + 'Driveclub' => 34927, + 'Dropbox' => 32620, + 'EA' => 34506, + 'EA Sports UFC' => 38468, + 'Easynet' => 33881, + 'eBay' => 32621, + 'Eclipse' => 32680, + 'EE' => 32661, + 'Elite: Dangerous' => 36684, + 'Epic Games Store' => 38828, + 'Escape from Tarkov' => 38108, + 'Etoro' => 36959, + 'Etsy' => 36422, + 'Eurosport Player' => 35819, + 'Evernote' => 34705, + 'Exchange Online' => 34536, + 'Expedia' => 36421, + 'Experian' => 38156, + 'Exponential-E' => 34409, + 'Facebook' => 32622, + 'Facebook Messenger' => 32623, + 'Faceit' => 37145, + 'Facetime' => 34604, + 'Fallout' => 35431, + 'Fandom' => 38690, + 'Far Cry' => 37176, + 'Fasthosts' => 35705, + 'Fifa' => 35471, + 'Find my iPhone' => 36123, + 'First Direct' => 33978, + 'First Trust Bank' => 38226, + 'Fitbit' => 36630, + 'Flickr' => 32624, + 'Fling' => 35165, + 'For Honor' => 35988, + 'Fortnite' => 36624, + 'Forza' => 37569, + 'Freedompop' => 35639, + 'Freesat' => 37594, + 'Freeview' => 35771, + 'Friday the 13th The Game' => 37563, + 'Funimation' => 37745, + 'Game of war' => 35229, + 'Gamma' => 34899, + 'Garmin' => 36990, + 'Garmin Connect' => 37192, + 'Gears of War' => 35939, + 'Ghost Recon' => 36007, + 'Giffgaff' => 33985, + 'Gigler' => 35790, + 'GitHub' => 32625, + 'Glide' => 38901, + 'Gmail' => 32626, + 'Go Daddy' => 34873, + 'Google' => 32627, + 'Google Calendar' => 38598, + 'Google Cloud' => 38536, + 'Google Drive' => 34273, + 'Google Hangouts' => 32629, + 'Google Home' => 36138, + 'Google Play' => 32628, + 'GoToMeeting' => 36505, + 'Gran Turismo' => 36680, + 'Great Western Railway' => 37808, + 'Grindr' => 35530, + 'GTA 5' => 34752, + 'Guild Wars 2' => 36407, + 'Gumtree' => 32756, + 'Halifax' => 32689, + 'Halo' => 35451, + 'Harry Potter: Wizards Unite' => 38688, + 'Hay Day' => 34788, + 'Hayu' => 38052, + 'Heart Internet' => 37623, + 'Hearthstone' => 38563, + 'Hermes' => 34949, + 'Hipchat' => 34866, + 'Hitman' => 36880, + 'Hive' => 39072, + 'HMRC' => 36961, + 'Home telecom' => 35959, + 'Hootsuite' => 32630, + 'HQ Trivia' => 37161, + 'HSBC' => 32686, + 'Hue' => 37811, + 'Hunt: showdown' => 38823, + 'Hyperoptic' => 36520, + 'iCloud' => 32663, + 'IG' => 37630, + 'iMessage' => 32664, + 'Imgur' => 32632, + 'IMVU' => 37177, + 'Indeed' => 38589, + 'Instagram' => 32633, + 'Internet Movie Database (IMDb)' => 36752, + 'Iomart' => 37180, + 'iPlayer' => 32755, + 'iTunes' => 32665, + 'ITV' => 34302, + 'Janet' => 35452, + 'Jira' => 34871, + 'John Lewis' => 36782, + 'Jurassic World Alive' => 37332, + 'Just Eat' => 36031, + 'KC' => 34130, + 'Kik' => 33352, + 'Kraken' => 36751, + 'Ladbrokes' => 35033, + 'LastPass' => 34778, + 'League of Legends' => 35048, + 'LinkedIn' => 32634, + 'Litebit' => 36837, + 'Lloyds Bank' => 32691, + 'M&S Bank' => 35457, + 'M24Seven' => 37150, + 'Madden' => 38458, + 'Mail.com' => 34800, + 'Mailbox' => 34836, + 'Mailchimp' => 38728, + 'Manx Telecom' => 35534, + 'Mastercard' => 37250, + 'McDonalds app' => 37374, + 'Meetup' => 34246, + 'Metro Bank' => 34970, + 'Microsoft Azure' => 32651, + 'Microsoft Teams' => 38184, + 'Minecraft' => 32635, + 'Mixer' => 38768, + 'Monzo' => 37591, + 'Moonfruit' => 35456, + 'MTV' => 34124, + 'Musical.ly' => 37140, + 'My Fitness Pal' => 36956, + 'My Vue' => 36329, + 'Namesco Ltd' => 35900, + 'National Lottery' => 34950, + 'Nationwide' => 32690, + 'NatWest' => 32684, + 'NBA 2k' => 37721, + 'Nest' => 35192, + 'Netflix' => 32636, + 'Neverwinter' => 35767, + 'NikePlus' => 38783, + 'Nintendo eShop' => 34100, + 'Nintendo Network' => 35516, + 'Nintendo Switch Online' => 37241, + 'No Man\'s Sky' => 37405, + 'NordVPN' => 38248, + 'Now TV' => 34406, + 'Nvidia' => 39068, + 'O2' => 32660, + 'Office 365' => 34538, + 'OkCupid' => 37331, + 'Omegle' => 39043, + 'OneDrive' => 32781, + 'Online.net' => 36174, + 'ooVoo' => 36586, + 'Orange' => 32676, + 'Origin' => 36419, + 'Origin Broadband' => 36052, + 'Outlook' => 32631, + 'Overwatch' => 35681, + 'OVH' => 36160, + 'Paddy Power' => 35032, + 'Paladins' => 36377, + 'Path of Exile' => 36487, + 'Paypal' => 35557, + 'PES' => 38590, + 'Photobucket' => 32638, + 'Pinterest' => 32639, + 'Player Unknown\'s Battlegrounds' => 36335, + 'Playstation Network' => 32668, + 'PlentyOfFish' => 36023, + 'Plusnet' => 32683, + 'Pokémon Go' => 35730, + 'Pokerstars' => 37440, + 'Post Office' => 32682, + 'Project Online' => 34539, + 'ProtonMail' => 38963, + 'Quickbooks Online' => 36583, + 'Quizup' => 34298, + 'Rackspace' => 34610, + 'Rainbow Six' => 35476, + 'Rakuten TV' => 37597, + 'RBS (Royal Bank of Scotland)' => 32688, + 'Realm Royale' => 37309, + 'Red Dead Redemption' => 37743, + 'Redbox' => 38791, + 'Reddit' => 34844, + 'Relish' => 34797, + 'Revolut' => 37365, + 'Roblox' => 35786, + 'Rocket League' => 35355, + 'Royal Mail' => 35776, + 'Runescape' => 35107, + 'Ruzzle' => 34479, + 'Ryanair' => 36003, + 'Sagepay' => 36781, + 'Sainsbury\'s Bank' => 35116, + 'Salesforce' => 38495, + 'Santander' => 32687, + 'Sarahah' => 36373, + 'Scottish Power' => 36041, + 'Sea of Thieves' => 37110, + 'Sharepoint Online' => 34540, + 'Shopify' => 38538, + 'Shutterstock' => 37448, + 'Signal' => 37070, + 'Sky' => 32782, + 'Sky Bet' => 35076, + 'Skype' => 32640, + 'Skype for Business' => 34537, + 'Slack' => 35934, + 'Slideshare' => 32641, + 'Smart Hub' => 35179, + 'Smartsheet' => 38723, + 'Smile' => 36661, + 'Smite' => 35407, + 'Snapchat' => 32642, + 'Soundcloud' => 36954, + 'Sourceforge' => 32643, + 'South Western Railway' => 37809, + 'Spotify' => 32644, + 'Squarespace' => 38784, + 'SSE' => 37058, + 'Star Citizen' => 39036, + 'Star Wars Battlefront' => 35551, + 'Starling Bank' => 38719, + 'Steam' => 32667, + 'Steep' => 37822, + 'Strava' => 37046, + 'Streamcenter' => 37016, + 'Summoners War' => 37419, + 'T-Mobile' => 32679, + 'Tado' => 36632, + 'Talkmobile' => 33988, + 'TalkTalk' => 32677, + 'Tango' => 33739, + 'Teamviewer' => 34615, + 'Telegram' => 34222, + 'Tesco Bank' => 34969, + 'Tesco Broadband' => 34086, + 'Tesco Mobile' => 35149, + 'The Co-operative Bank' => 34971, + 'The Crew 2' => 36555, + 'The Division' => 35561, + 'The elder scrolls online' => 36400, + 'The People\'s Operator' => 35150, + 'The Simpsons Tapped out' => 35077, + 'Thinkmoney' => 36331, + 'Ticketmaster' => 36786, + 'Tiktok' => 38726, + 'Tinder' => 34240, + 'TomTom Live' => 34918, + 'Transferwise' => 38565, + 'Trove' => 38826, + 'TSB Bank' => 33970, + 'Tumblr' => 32645, + 'TuneIn' => 37973, + 'Tweakbox' => 38342, + 'Twitch' => 35022, + 'Twitter' => 32646, + 'Uber' => 37498, + 'Uber Eats' => 38271, + 'Udemy' => 37717, + 'UKfast' => 36838, + 'Ulster Bank' => 36071, + 'Unibet' => 36055, + 'Uplay PC' => 34691, + 'UPS' => 38744, + 'Viber' => 33349, + 'Vimeo' => 32647, + 'Virgin Media' => 32675, + 'Visa' => 37237, + 'Vistaprint' => 35130, + 'Vodafone' => 32659, + 'Waitrose' => 36964, + 'Warface' => 38766, + 'Warframe' => 36367, + 'Wattpad' => 34696, + 'Waze' => 33407, + 'Webex' => 34161, + 'Weebly' => 38547, + 'Weight Watchers' => 35663, + 'WeTransfer' => 32648, + 'Whatsapp' => 32649, + 'Whisper' => 37028, + 'Wikipedia' => 32650, + 'William Hill' => 35029, + 'Wish' => 39040, + 'Wix' => 37233, + 'Wordpress.com' => 32652, + 'World of Tanks' => 35525, + 'World of Warcraft' => 35052, + 'World of Warships' => 36639, + 'WWE Network' => 38085, + 'Xbox Live' => 32666, + 'Xero' => 37500, + 'XLN Telecom' => 33989, + 'Yahoo' => 32653, + 'Yahoo Mail' => 32654, + 'Yahoo Messenger' => 32655, + 'Yammer' => 36955, + 'Yelp' => 32656, + 'Yorkshire Bank' => 34968, + 'Yorkshire Building Society' => 38224, + 'Youtube' => 32657, + 'Youtube Music' => 37587, + 'Yubo' => 37246, + 'Z1 Battle Royale' => 35490, + 'Zen Internet' => 33874, + 'ZoHo' => 36039, + 'Zone Broadband' => 36994, + 'Zoom' => 37946, + 'Zynga' => 32658, + ), + 'United States' => array( + '1and1' => 34817, + '1Password' => 36441, + '2600hertz' => 37692, + '2k' => 34768, + '4chan' => 37567, + '7 Days to Die' => 35947, + '8x8' => 34314, + 'ABC' => 38902, + 'Abebooks' => 36535, + 'Absolver' => 37366, + 'Access One' => 36063, + 'Acorns' => 37647, + 'Adams Networks' => 33556, + 'Adobe Connect' => 34134, + 'Adobe Creative Cloud' => 34551, + 'ADP' => 37657, + 'ADT' => 38502, + 'Adyen' => 37611, + 'Agar.io' => 38216, + 'Aio Wireless' => 34098, + 'Air Canada' => 20003, + 'Airbnb' => 34335, + 'AireSpring' => 35893, + 'Airnow.gov' => 37658, + 'Akamai' => 35447, + 'Alaska Airlines' => 20004, + 'Alaska Communications' => 36040, + 'Albion Online' => 38795, + 'Alexa' => 35910, + 'AliExpress' => 37395, + 'Allegiant Air' => 20005, + 'Ally' => 34791, + 'Amazon' => 20006, + 'Amazon Prime Music' => 34710, + 'Amazon Prime Video' => 33370, + 'Amazon Web Services' => 10147, + 'American Airlines' => 20007, + 'American Express' => 35958, + 'American Messaging' => 34128, + 'Amino Apps' => 37290, + 'Ammyy' => 36575, + 'Amtrak' => 20008, + 'Ancestry' => 38296, + 'Anno 1800' => 38413, + 'Anthem' => 37746, + 'Antietam' => 37051, + 'Anydesk' => 37406, + 'AOL' => 33419, + 'Apex Legends' => 38111, + 'App Store' => 35575, + 'Apple Maps' => 36125, + 'Apple Music' => 35241, + 'Apple News' => 36126, + 'Apple Store' => 34447, + 'Apple TV' => 36058, + 'Apple TV+' => 38318, + 'Appriver' => 37074, + 'AppValley' => 37749, + 'Arbuckle' => 34489, + 'ArcheAge' => 34876, + 'ARK: Survival Evolved' => 36350, + 'Arlo' => 36779, + 'Armstrong' => 34027, + 'Arvest Bank' => 37148, + 'Arvig' => 34919, + 'Asana' => 35828, + 'Assassin\'s Creed' => 35005, + 'AT&T' => 20010, + 'Atlantic Broadband' => 33437, + 'Authorize.net' => 34821, + 'Autotask' => 37579, + 'BabyTEL' => 35631, + 'Backblaze' => 35483, + 'Badoo' => 35993, + 'Bandwidth' => 35667, + 'Bank of America' => 20011, + 'Barclays' => 37639, + 'BART' => 20012, + 'Batman The Telltale Series' => 35896, + 'Battalion 1944' => 37002, + 'Battleborn' => 35718, + 'Battlefield' => 36091, + 'Battlerite' => 36820, + 'BB&T' => 35658, + 'Beats Music' => 34294, + 'beIN' => 37355, + 'Bejeweled' => 35904, + 'Bendbroad' => 34884, + 'Best Buy' => 34329, + 'BET' => 34125, + 'Bethesda' => 38316, + 'Binance' => 36818, + 'Bing' => 20014, + 'Birch Communications' => 33549, + 'Bitbucket' => 35414, + 'Bitfinex' => 36787, + 'Bitflyer' => 36789, + 'Bitstamp' => 34023, + 'Bittrex' => 36788, + 'Black Desert Online' => 37108, + 'BlackBerry' => 20015, + 'Blade and Soul' => 35511, + 'Blizzard Battle.net' => 34486, + 'Blogger' => 20016, + 'Blue Jay Wireless' => 35464, + 'Bluebird' => 37362, + 'Bluehost' => 33418, + 'BlueJeans' => 37509, + 'BMW ConnectedDrive' => 38471, + 'BNY Mellon' => 35674, + 'Boingo' => 37377, + 'Booking.com' => 34330, + 'Boom Beach' => 34364, + 'Box' => 32775, + 'Brawl Stars' => 38312, + 'BT' => 38338, + 'Buckeye Cablesystem' => 34029, + 'Buffer' => 36013, + 'Bullet Force' => 37109, + 'Bumble' => 35823, + 'C Spire' => 38219, + 'Cable One' => 20019, + 'Call of Duty' => 34148, + 'CallTower' => 35365, + 'Caltrain' => 20021, + 'Candy Crush' => 34024, + 'Candy Crush Soda Saga' => 35171, + 'Canva' => 36778, + 'Capital One' => 20022, + 'Cash App' => 38685, + 'CBSSports' => 35826, + 'Century National Bank' => 37690, + 'CenturyLink' => 20023, + 'Change.org' => 35616, + 'Charles Schwab' => 20078, + 'Chase' => 20025, + 'Chegg' => 36054, + 'Chicago Transit Authority' => 20026, + 'Chime' => 39050, + 'Chrome Web Store' => 34116, + 'Cincinnati Bell' => 33422, + 'Cirra Networks' => 36357, + 'Citi' => 20027, + 'Citizens Bank' => 37748, + 'Civilization' => 35869, + 'Clash of Clans' => 33550, + 'Clash Royale' => 35587, + 'Classlink' => 36821, + 'Clear' => 33423, + 'Cloudflare' => 32542, + 'Cloudsmith' => 35946, + 'Cloudtrax' => 37528, + 'CNET' => 33341, + 'CNN' => 34141, + 'Cogent' => 34026, + 'Coinbase' => 36175, + 'Comcast' => 20029, + 'Comedy Central' => 34126, + 'Common App' => 36726, + 'Comporium' => 36032, + 'Conan Exiles' => 37195, + 'Concur' => 36730, + 'Confluence' => 37540, + 'ConnectWise' => 37493, + 'Consolidated' => 34030, + 'Consolidated Edison' => 35679, + 'Consumer Cellular' => 37761, + 'Copy.com' => 34231, + 'Coredial' => 35454, + 'Costco' => 37061, + 'Counter-strike' => 34886, + 'Cox' => 20030, + 'Crackle' => 35349, + 'Craigslist' => 20031, + 'Credit One Bank' => 37760, + 'Cricket Wireless' => 20032, + 'Crown Castle' => 35812, + 'Crunchyroll' => 35114, + 'Cryptopia' => 36973, + 'Dailymotion' => 37598, + 'Dark Souls.' => 35710, + 'Dauntless' => 37204, + 'DayZ' => 37751, + 'Dazn' => 37497, + 'DC Universe Online' => 37059, + 'Dead By Daylight' => 35760, + 'Deezer' => 36424, + 'Defiance 2050' => 37364, + 'Delta Air Lines' => 20033, + 'Destiny' => 34761, + 'DeviantArt' => 34888, + 'Di.fm' => 35645, + 'Diablo' => 34385, + 'DirecTV' => 20034, + 'Directv Now' => 35933, + 'Discord' => 35795, + 'Dish Network' => 20035, + 'Disney World' => 35837, + 'Disney+' => 38800, + 'Disqus' => 34145, + 'Diversity Lottery' => 38472, + 'Dlive' => 38470, + 'Docker' => 37817, + 'Doom' => 35717, + 'Doordash' => 37581, + 'Dota 2' => 34304, + 'Doublelist' => 37580, + 'Downforeveryoneorjustme' => 34758, + 'Draftkings' => 37036, + 'Dragon Ball' => 35858, + 'Dramafever' => 36064, + 'DreamHost' => 35926, + 'Driveclub' => 35891, + 'Dropbox' => 20036, + 'Duckduckgo' => 35650, + 'Duke Energy' => 35871, + 'Duolingo' => 35942, + 'Dyl' => 37383, + 'Dyn' => 35707, + 'E-Trade' => 20037, + 'EA' => 34499, + 'EA Sports UFC' => 35715, + 'Eagle Communications ' => 36027, + 'Earthlink' => 32776, + 'Eatel' => 35448, + 'eBay' => 20038, + 'Ecobee' => 37163, + 'eFax' => 38664, + 'Electric Power Board' => 35778, + 'Elite: Dangerous' => 36478, + 'Ello' => 34906, + 'Endicia' => 36839, + 'Engine Yard' => 33966, + 'eNom' => 35901, + 'EPB Chattanooga' => 35513, + 'Epic Games Store' => 37756, + 'Escape from Tarkov' => 37424, + 'ESPN' => 33335, + 'ESPN Plus' => 38320, + 'Etherdelta' => 36858, + 'Etsy' => 33366, + 'Eve Online' => 35721, + 'Eve Valkyrie' => 35884, + 'Evernote' => 34706, + 'Everquest' => 38337, + 'Exchange Online' => 34534, + 'Exede' => 33557, + 'Expedia' => 34332, + 'Experian' => 38155, + 'ExpressVPN' => 37544, + 'Faceapp' => 38695, + 'Facebook' => 10198, + 'Facebook Messenger' => 20039, + 'Faceit' => 38543, + 'Facetime' => 34606, + 'FAFSA' => 37691, + 'FairPoint' => 33994, + 'Fallout' => 35430, + 'Family Search' => 33439, + 'Fandango' => 34481, + 'Fandom' => 34317, + 'Fanduel' => 37035, + 'Fanfiction' => 37101, + 'Far Cry' => 35713, + 'FastMail' => 35779, + 'Fatcow' => 34882, + 'Fax2mail' => 38665, + 'FedEx' => 35843, + 'Feedly' => 34704, + 'Fidelity' => 36738, + 'Fifa' => 35470, + 'Final Fantasy' => 35860, + 'Find my iPhone' => 38662, + 'First Communications ' => 36062, + 'FirstEnergy' => 35994, + 'FirstLight' => 34879, + 'Fitbit' => 35800, + 'Fite' => 38794, + 'Fiverr' => 37054, + 'Flickr' => 20040, + 'Fling' => 37353, + 'Flipboard' => 33491, + 'Florida Power & Light' => 35699, + 'Fonality' => 34312, + 'For Honor' => 35984, + 'Forge Of Empires' => 35886, + 'Fortnite' => 36375, + 'Forza' => 36817, + 'Fox News' => 35880, + 'Fox Sports Go' => 37164, + 'Frankfort PlantBoard' => 35466, + 'Freedompop' => 35657, + 'Freepik' => 36739, + 'Friday the 13th The Game' => 36348, + 'Frii' => 35668, + 'Frontier' => 20041, + 'Frontier Airlines' => 20042, + 'FuboTV' => 36658, + 'Funimation' => 36665, + 'Fuze' => 35847, + 'FXNOW' => 37504, + 'G-Portal' => 37154, + 'G2A.com' => 35898, + 'Game of Thrones Conquest' => 37669, + 'Game of war' => 35228, + 'Gamebattles' => 37753, + 'Gameloft' => 35964, + 'Gamestop' => 36780, + 'Gang Beasts' => 36926, + 'Garmin' => 35554, + 'Garmin Connect' => 35801, + 'Gatehub' => 36841, + 'GCI' => 35633, + 'GDAX' => 36791, + 'Gears of War' => 35848, + 'Geeking' => 37251, + 'Gemini' => 36811, + 'Gems of war' => 38801, + 'Geocaching' => 35770, + 'Gfycat' => 38504, + 'Ghost' => 38720, + 'Ghost Recon' => 36000, + 'Ghosttunes' => 34883, + 'GitHub' => 10004, + 'Gitlab' => 37146, + 'Glassdoor' => 35740, + 'Glide' => 34016, + 'Glitch' => 38721, + 'Gmail' => 20043, + 'Go Daddy' => 33416, + 'GOG.com' => 34287, + 'Google' => 10200, + 'Google Calendar' => 38597, + 'Google Cloud' => 37380, + 'Google Drive' => 34271, + 'Google Fiber' => 33421, + 'Google Hangouts' => 20046, + 'Google Home' => 36137, + 'Google Play' => 20045, + 'GoToMeeting' => 33489, + 'Gran Turismo' => 36347, + 'Grande' => 34404, + 'Greenlight' => 37628, + 'Grindr' => 35529, + 'Groove Music' => 33972, + 'Groupme' => 35739, + 'Groupon' => 35709, + 'Growtopia' => 36835, + 'Grubhub' => 37693, + 'GTA 5' => 33995, + 'Guild Wars 2' => 35060, + 'H&R Block' => 34328, + 'Halo' => 35418, + 'Halo Wars' => 36035, + 'Happn' => 37013, + 'Hargray' => 34142, + 'Harry Potter: Wizards Unite' => 38593, + 'Hashflare' => 37038, + 'Hawaiian Airlines' => 20047, + 'Hawaiian Telcom' => 33436, + 'Hay Day' => 34367, + 'Hayu' => 37198, + 'HBO Go' => 34340, + 'HBO Now' => 38697, + 'Healthcare.gov' => 34011, + 'Hearthstone' => 36834, + 'Heartland' => 38803, + 'Heroku' => 33965, + 'HiDive' => 37527, + 'HInge' => 37625, + 'Hipchat' => 34865, + 'HitBTC' => 36925, + 'Hitman' => 35585, + 'Hive' => 37571, + 'Honeywell' => 38110, + 'Hootsuite' => 20048, + 'Hostgator' => 33417, + 'Hostmonster' => 35931, + 'Hotels.com' => 34334, + 'Hotwire' => 34331, + 'HouseParty' => 37356, + 'HQ Trivia' => 36815, + 'HSBC' => 35673, + 'Hue' => 37514, + 'HughesNet' => 32787, + 'Hulu' => 33331, + 'Humanity' => 36735, + 'Hunt: showdown' => 37006, + 'Hurricane Electric' => 35811, + 'I3 Broadband' => 36286, + 'IBM Cloud' => 37649, + 'iCloud' => 20049, + 'ICQ' => 34766, + 'iFunny' => 38294, + 'IGTV' => 37317, + 'iHeartRadio' => 33369, + 'Illinois Century Network' => 36086, + 'IMDb Freedrive' => 37960, + 'iMessage' => 20050, + 'Imgur' => 20051, + 'IMVU' => 36523, + 'Inbox' => 34318, + 'inContact' => 35836, + 'Indeed' => 35864, + 'Ingress' => 35764, + 'Injustice 2' => 36526, + 'Inmotion' => 34759, + 'Instagram' => 20052, + 'Integra' => 33554, + 'Interactive Brokers' => 34115, + 'Intermedia' => 33973, + 'Internet Movie Database (IMDb)' => 33337, + 'Intralinks' => 38667, + 'Ipage' => 35659, + 'iRacing' => 35957, + 'Iridium' => 35652, + 'Ironsight' => 37142, + 'IRS' => 35542, + 'iTunes' => 20053, + 'iTunes Connect' => 36489, + 'iTunes Match' => 36059, + 'iWork' => 36124, + 'Jabber' => 36524, + 'Jackbox' => 38790, + 'JetBlue Airways' => 20054, + 'Jira' => 34870, + 'Jive' => 35453, + 'JP Morgan' => 37034, + 'Juno' => 32786, + 'Jurassic World Alive' => 37256, + 'Kayak' => 34338, + 'Keek' => 33770, + 'Kik' => 32770, + 'Kraken' => 36660, + 'Kucoin' => 36962, + 'last.fm' => 35634, + 'LastPass' => 35541, + 'LawBreakers' => 36527, + 'Layer3 TV' => 37378, + 'Leaco' => 35665, + 'League of Legends' => 34111, + 'Lifesize' => 37003, + 'Lightpath' => 35685, + 'Limebike' => 37205, + 'Limelight Networks' => 35462, + 'Line' => 33738, + 'LinkedIn' => 20055, + 'Linode' => 35907, + 'Liquid Web' => 34825, + 'LiveLeak' => 38273, + 'Liveperson' => 35417, + 'Logix' => 38295, + 'Logmein' => 33488, + 'Lola Wireless' => 35905, + 'Lowe\'s' => 38297, + 'LS Networks' => 35703, + 'Lumos Networks' => 34217, + 'Lyft' => 36571, + 'Lynda' => 35781, + 'Madden' => 37747, + 'Maguss' => 37047, + 'Mail.com' => 34798, + 'Mailbox' => 34831, + 'Mailchimp' => 36017, + 'MARTA' => 20056, + 'Marvel' => 38792, + 'Marvel Contest of Champions' => 37005, + 'Maryland Transit Administration (MTA)' => 20017, + 'Mass Effect ' => 36057, + 'Mastercard' => 37249, + 'MaxxSouth ' => 36095, + 'MBTA' => 20057, + 'McDonalds app' => 36369, + 'Media Temple' => 35950, + 'Mediacom' => 20058, + 'Meetme' => 37042, + 'Meetup' => 34245, + 'Megapath' => 33420, + 'Merrill Lynch' => 37032, + 'Metra' => 20059, + 'Metro PCS' => 20060, + 'MetroCast' => 34405, + 'Metrolink' => 20061, + 'Metronetinc' => 35890, + 'MHz Choice' => 37297, + 'Miami Dade Transit' => 20062, + 'Microsoft Azure' => 32547, + 'Microsoft Teams' => 38018, + 'Microsoft VLSC' => 38187, + 'Midcontinent Media' => 33552, + 'Mimecast' => 35783, + 'Minecraft' => 20063, + 'Mint' => 36589, + 'MintSim' => 36438, + 'Mitel' => 36005, + 'Mixer' => 36525, + 'MLB The Show' => 35711, + 'MLB TV' => 35712, + 'Mobile legends' => 37394, + 'Mobile Strike' => 36476, + 'Momentum Telecom' => 36733, + 'Moneylion' => 38303, + 'Monster Hunter' => 37007, + 'Mordhau' => 38497, + 'Moviepass' => 37004, + 'Movies Anywhere' => 38771, + 'MovieTickets' => 36178, + 'MSL Live' => 37107, + 'MTV' => 34133, + 'MU Legend' => 36792, + 'Music Unlimited' => 35909, + 'Musical.ly' => 36659, + 'My Fitness Pal' => 35803, + 'My Social Security' => 37627, + 'Naruto-Storm' => 35845, + 'National Grid NY' => 36024, + 'NBA 2k' => 35714, + 'NBC Sports Live Extra' => 34295, + 'NBCNews.com' => 33340, + 'NCTC' => 36344, + 'Need for Speed' => 35428, + 'NEMR' => 35514, + 'Nest' => 35190, + 'Net10 Wireless' => 34090, + 'netBlazr' => 35656, + 'Neteller' => 38321, + 'Netflix' => 20065, + 'Netsuite' => 35743, + 'Nettalk' => 36732, + 'Network Solutions' => 33548, + 'NetZero' => 32785, + 'Neverwinter' => 35603, + 'New Jersey Transit' => 20066, + 'New York MTA' => 20067, + 'New York Times' => 33339, + 'Newegg' => 35438, + 'NewWave Communications' => 36026, + 'Nextiva' => 34850, + 'NFL Network' => 36572, + 'NHL.tv' => 36816, + 'Nicehash' => 37037, + 'NikePlus' => 35805, + 'Nintendo eShop' => 34099, + 'Nintendo Network' => 35515, + 'Nintendo Switch Online' => 37240, + 'No Man\'s Sky' => 35793, + 'NordVPN' => 37545, + 'North State' => 36840, + 'Northland Communications' => 38035, + 'Norwood Light' => 35738, + 'NTT Communications' => 35856, + 'NuGet' => 36740, + 'Oculus' => 38253, + 'Office 365' => 34532, + 'OkCupid' => 35902, + 'Okta' => 35742, + 'Omegle' => 36522, + 'OneDrive' => 32780, + 'Onelogin' => 38439, + 'Ooma' => 35628, + 'ooVoo' => 34085, + 'Opera' => 38406, + 'Optimum / Cablevision' => 20020, + 'OptionsHouse' => 20068, + 'optionsXpress' => 20069, + 'Oracle Cloud' => 38033, + 'Orbitz' => 34337, + 'Origin' => 34113, + 'OS X Update' => 36127, + 'Outlook' => 10205, + 'Overdrive' => 35855, + 'Overwatch' => 35680, + 'Pacific Northern Gas ' => 35807, + 'Page Plus' => 34012, + 'Pagely' => 33974, + 'Paladins' => 35857, + 'Pandora' => 20070, + 'Paperspace' => 37200, + 'Paragon' => 36359, + 'PATCO' => 20071, + 'PATH' => 20072, + 'Path of Exile' => 34823, + 'Patreon' => 38503, + 'Paypal' => 20073, + 'pCloud' => 36588, + 'PenTeleData' => 34401, + 'Periscope' => 35595, + 'Personal Capital' => 36969, + 'PES' => 37951, + 'PG&E' => 35677, + 'PGA Tour Live' => 37235, + 'Phonepower' => 35361, + 'Photobucket' => 20074, + 'Pinterest' => 20075, + 'Planetside2' => 35787, + 'Player Unknown\'s Battlegrounds' => 36135, + 'Playstation Network' => 20076, + 'Playstation Vue' => 35188, + 'PlentyOfFish' => 35799, + 'Plex' => 35573, + 'PNC' => 33333, + 'Pokémon Duel' => 35966, + 'Pokémon Go' => 35725, + 'Pokerstars' => 38749, + 'Poloniex' => 36349, + 'Postmates' => 36774, + 'Powerschool' => 35867, + 'Prey' => 37295, + 'Priceline' => 34333, + 'Project Online' => 34535, + 'Proofpoint' => 38666, + 'ProtonMail' => 36136, + 'Quake Champions' => 36773, + 'Quickbooks Online' => 35761, + 'Quicken' => 36614, + 'Quizlet' => 34322, + 'Quizup' => 34296, + 'Quora' => 34341, + 'Rabb.it' => 36819, + 'Rackspace' => 34609, + 'Rain World Game' => 36042, + 'Rainbow Six' => 35463, + 'Razer' => 38698, + 'RCN' => 32784, + 'Realm Royale' => 37287, + 'Red Dead Redemption' => 37600, + 'Redbox' => 37213, + 'Reddit' => 33342, + 'Reflexion' => 38733, + 'RingCentral' => 34311, + 'Rise Broadband' => 35458, + 'Robinhood' => 35706, + 'Roblox' => 34820, + 'Rocket League' => 35251, + 'RocketRez' => 35784, + 'Roku' => 37194, + 'Royal Games' => 38218, + 'Runescape' => 34804, + 'Runkeeper' => 35802, + 'Runtastic' => 35804, + 'Rust' => 37755, + 'Ruzzle' => 33969, + 'Safelink Wireless' => 35467, + 'Safenet' => 37538, + 'Salesforce' => 32773, + 'Santander Bank' => 38656, + 'Sarahah' => 36365, + 'Schooldesk' => 35468, + 'Scottrade' => 20079, + 'ScreenConnect' => 35661, + 'Scum' => 37464, + 'Sea of Thieves' => 36995, + 'SEC Network' => 37757, + 'Secom' => 36972, + 'Second Life' => 37612, + 'SEPTA' => 20080, + 'Service Electric' => 33553, + 'Sharebuilder' => 20081, + 'Sharefile' => 37513, + 'Sharepoint Online' => 34533, + 'Shentel' => 35666, + 'Shopify' => 37555, + 'Shoretel' => 35846, + 'Showtime Anytime' => 35591, + 'Shutterstock' => 35704, + 'Signal' => 37071, + 'SignupGenius' => 35636, + 'Simple' => 34790, + 'Simple Mobile' => 33979, + 'Siri' => 38339, + 'SiriusXM' => 37048, + 'Skillshare' => 35775, + 'Skrill' => 37257, + 'Skype' => 20082, + 'Skype for Business' => 35350, + 'Skyscanner' => 38645, + 'SkySwitch' => 36664, + 'SkyWest' => 20084, + 'Slack' => 35437, + 'Slashdot' => 36615, + 'Sleeper' => 37455, + 'Slideshare' => 20085, + 'Sling' => 35155, + 'Smart Hub' => 35178, + 'Smartsheet' => 38310, + 'SmartThings' => 37102, + 'Smite' => 34802, + 'SNAP EBT' => 34006, + 'Snapchat' => 20086, + 'Socket' => 37411, + 'Sonic.net' => 34403, + 'Soundcloud' => 34351, + 'Sourceforge' => 20087, + 'South Central Communications' => 35759, + 'Southern California Edison' => 35700, + 'Southwest Airlines' => 20088, + 'Spectrum' => 20024, + 'Speedtest' => 37354, + 'Spirit Communications' => 35808, + 'SplashID' => 35594, + 'Spotify' => 20090, + 'Sprint' => 20091, + 'Square' => 37053, + 'Squarespace' => 36573, + 'Stack Exchange' => 34319, + 'Stackoverflow' => 34258, + 'Stadia' => 38302, + 'Staminus' => 34608, + 'Stamps.com' => 36662, + 'Star Citizen' => 36477, + 'Star Wars Battlefront' => 35459, + 'Starbucks' => 37210, + 'Starz' => 38291, + 'Steam' => 20092, + 'Steep' => 36011, + 'Straight Talk' => 34097, + 'Strava' => 36047, + 'Streamlabs' => 37206, + 'Strife' => 35853, + 'Stripe' => 38668, + 'Suddenlink' => 20093, + 'Suitebox' => 37211, + 'Summit Broadband' => 35617, + 'Summoners War' => 37409, + 'SunTrust Bank' => 37346, + 'Surfline' => 36341, + 'SurveyMonkey' => 35963, + 'T-Mobile' => 20097, + 'T. Rowe Price' => 37033, + 'Talkray' => 34750, + 'Tango' => 33728, + 'Target' => 34320, + 'Taxslayer' => 36018, + 'TD Ameritrade' => 20094, + 'TD Bank' => 35672, + 'TDS Telecom' => 33558, + 'Teamviewer' => 34343, + 'Tekken' => 37196, + 'Telecharge' => 37220, + 'Telegram' => 34227, + 'Tennis TV' => 37040, + 'TERA' => 37105, + 'Tesla' => 37152, + 'The Crew 2' => 35809, + 'The Culling' => 37752, + 'The Division' => 35558, + 'The elder scrolls online' => 35535, + 'The Huffington Post' => 33334, + 'The Simpsons Tapped out' => 34702, + 'The Weather Channel' => 33336, + 'Thingiverse' => 38732, + 'Threads' => 38983, + 'Threema' => 35892, + 'TIAA ' => 35597, + 'Ticketmaster' => 36534, + 'Tidal' => 37512, + 'Tiktok' => 38367, + 'Tinder' => 34237, + 'Titanfall' => 35897, + 'Tivo' => 37001, + 'Todoist' => 36461, + 'Toggl' => 36993, + 'TPx Communications' => 34402, + 'TracFone Wireless' => 20099, + 'Tradeking' => 33768, + 'TradeSatoshi' => 37106, + 'TradeStation' => 20100, + 'Transferwise' => 37199, + 'Travelocity' => 34336, + 'Trello' => 34796, + 'Trove' => 35363, + 'Trusted Id' => 36636, + 'TSYS' => 36517, + 'Tumblr' => 20101, + 'TuneIn' => 35221, + 'TurboTax' => 34327, + 'TV Time' => 37197, + 'TW Telecom' => 32783, + 'Tweakbox' => 37750, + 'Tweetdeck' => 39009, + 'Twitch' => 34308, + 'Twitter' => 10204, + 'Uber' => 36570, + 'Uber Eats' => 37648, + 'Udacity' => 35842, + 'Udemy' => 35644, + 'UFC' => 36736, + 'UMG Gaming' => 36528, + 'Uncharted' => 35716, + 'United Airlines' => 20104, + 'Untappd' => 37363, + 'Uplay PC' => 34381, + 'UPS' => 34321, + 'Upwork' => 35436, + 'US Bank' => 20106, + 'US Cellular' => 20103, + 'USA Mobility' => 34129, + 'USPS' => 34259, + 'Utah Broadband' => 36342, + 'Vainglory' => 37203, + 'Vanguard' => 37011, + 'Vectren' => 35872, + 'Venmo' => 37209, + 'Verizon' => 20107, + 'Vero' => 37062, + 'Viaero' => 37508, + 'Viasat' => 38298, + 'Viber' => 32769, + 'Viewster' => 34323, + 'Viki' => 36065, + 'Vimeo' => 20110, + 'Vine' => 33368, + 'Virgin Mobile' => 34724, + 'Visa' => 37239, + 'Visible' => 38605, + 'Visual Studio Team Services' => 37463, + 'Vlive' => 36574, + 'Vonage' => 34315, + 'Voxer' => 33492, + 'VRChat' => 36991, + 'VRV' => 36640, + 'Vudu' => 34109, + 'Vyve Broadband' => 36012, + 'W3Schools' => 35887, + 'Waiter.com' => 36776, + 'Walmart Family' => 35465, + 'Walmart.com' => 33338, + 'War Thunder' => 37318, + 'Warface' => 37510, + 'Warframe' => 35825, + 'Washington Metropolitan Area Transit Authority' => 20111, + 'Wattpad' => 34693, + 'Wave Broadband' => 34028, + 'Waze' => 33382, + 'Webassign' => 35873, + 'Webex' => 33490, + 'Webhosting.net' => 35435, + 'Webs' => 35895, + 'Weebly' => 34910, + 'Weight Watchers' => 35646, + 'Wells Fargo' => 20112, + 'Wemo' => 37593, + 'Westman' => 35359, + 'WeTransfer' => 20113, + 'Whatsapp' => 10136, + 'Whisper' => 36881, + 'Wikipedia' => 20115, + 'Wilcoinc' => 35696, + 'Wildstar' => 36475, + 'William Hill' => 38900, + 'Windstream' => 20117, + 'Wish' => 38154, + 'Wix' => 35596, + 'Wordpress.com' => 20118, + 'Workday' => 37314, + 'World of Tanks' => 35357, + 'World of Warcraft' => 34263, + 'World of Warships' => 36637, + 'World War 3' => 37599, + 'World War Z' => 38405, + 'WOW' => 20114, + 'WP Engine' => 33975, + 'Wunderground' => 35948, + 'Wunderlist' => 35839, + 'WWE Network' => 36056, + 'Xbox Live' => 20119, + 'Xfinity Flex' => 38412, + 'XO' => 32777, + 'Yahoo' => 10203, + 'Yahoo Mail' => 20120, + 'Yahoo Messenger' => 20121, + 'Yammer' => 35559, + 'Yelp' => 20122, + 'Youtube' => 34651, + 'Youtube Music' => 37461, + 'Youtube TV' => 37296, + 'Yubo' => 37720, + 'Z1 Battle Royale' => 35146, + 'Zayo' => 35866, + 'Zelle' => 38683, + 'Zendesk' => 35854, + 'Zillow' => 33367, + 'ZoHo' => 34144, + 'Zoom' => 37349, + 'Zwift' => 38167, + 'Zynga' => 20123, + ), + 'New Zealand' => array( + '2degrees' => 33886, + '4chan' => 38270, + 'Alexa' => 36920, + 'Amurit.net' => 37710, + 'Anthem' => 38210, + 'ANZ' => 33888, + 'Apex Legends' => 38134, + 'Apple Store' => 34457, + 'ASB' => 33905, + 'beIN' => 38493, + 'Bigpipe' => 37704, + 'Bing' => 33889, + 'Blizzard Battle.net' => 38465, + 'BNZ' => 33907, + 'Call of Duty' => 34150, + 'CallPlus' => 33885, + 'CCL' => 37705, + 'Counter-strike' => 36854, + 'Crunchyroll' => 38146, + 'Cryptopia' => 36963, + 'Dead By Daylight' => 37434, + 'Destiny' => 38942, + 'Discord' => 38609, + 'Dota 2' => 36415, + 'EA' => 34505, + 'eBay' => 33891, + 'Evernote' => 35914, + 'Facebook' => 33892, + 'Facebook Messenger' => 33893, + 'Facetime' => 34587, + 'Fifa' => 38400, + 'Flip' => 37706, + 'Fortnite' => 36655, + 'Gmail' => 33894, + 'Google' => 33895, + 'Google Drive' => 36759, + 'Google Hangouts' => 33896, + 'Google Play' => 38525, + 'Gran Turismo' => 36948, + 'Grindr' => 38402, + 'GTA 5' => 37277, + 'iCloud' => 33921, + 'iMessage' => 33922, + 'Inspire Net' => 35445, + 'Instagram' => 33915, + 'iTunes' => 33923, + 'Kik' => 33914, + 'Kiwibank' => 33906, + 'League of Legends' => 38692, + 'Lightbox' => 35504, + 'LinkedIn' => 33897, + 'Minecraft' => 38617, + 'My Fitness Pal' => 37635, + 'myob' => 38926, + 'MyRepublic' => 34931, + 'NBA 2k' => 38785, + 'Neon' => 37707, + 'Netflix' => 34857, + 'Nzdating' => 37708, + 'Office 365' => 37171, + 'OneDrive' => 36863, + 'Orcon' => 33883, + 'Origin' => 36887, + 'Outlook' => 33918, + 'Overwatch' => 36416, + 'Pandora' => 33919, + 'Pinterest' => 33898, + 'Player Unknown\'s Battlegrounds' => 36362, + 'Playstation Network' => 34858, + 'Pokémon Go' => 35733, + 'Rabodirect' => 34980, + 'Rainbow Six' => 36610, + 'Reddit' => 34860, + 'Roblox' => 37662, + 'Skinny' => 37709, + 'Sky TV' => 33887, + 'Skype' => 33912, + 'Slingshot' => 34737, + 'Snapchat' => 33908, + 'Spark' => 33884, + 'Spotify' => 33910, + 'Steam' => 34225, + 'Tinder' => 34859, + 'Trade Me' => 33916, + 'Trustpower' => 37703, + 'Twitch' => 36540, + 'Twitter' => 33899, + 'Viber' => 33909, + 'Vodafone' => 33882, + 'Voxer' => 33913, + 'Wattpad' => 34697, + 'WeChat' => 33920, + 'Westpac' => 33900, + 'Whatsapp' => 33917, + 'Wikipedia' => 33901, + 'World of Warcraft' => 38814, + 'Xbox Live' => 34284, + 'Xero' => 35929, + 'Yahoo' => 33902, + 'Yahoo Mail' => 33903, + 'Youtube' => 33904, + 'Z1 Battle Royale' => 37266, + ), + 'België' => array( + '2dehands.be' => 34257, + 'Apex Legends' => 38141, + 'App Store' => 38555, + 'Apple Store' => 38925, + 'Argenta' => 32491, + 'Bancontact Mister Cash' => 33976, + 'Base' => 10207, + 'Battlefield' => 38444, + 'Belfius' => 32545, + 'Binance' => 36934, + 'Binck' => 32388, + 'Blizzard Battle.net' => 38810, + 'BNP Paribas Fortis' => 32543, + 'Bolero' => 37619, + 'Bpost' => 37157, + 'Bwin' => 34872, + 'Call of Duty' => 35536, + 'Clash Royale' => 38948, + 'Counter-strike' => 38245, + 'Crelan' => 37614, + 'Dead By Daylight' => 37445, + 'Deezer' => 33828, + 'Destiny' => 38559, + 'Deutsche Bank' => 34140, + 'Discord' => 37391, + 'Dommel' => 33977, + 'Dota 2' => 38478, + 'Dropbox' => 32525, + 'EA' => 34841, + 'eBay' => 33858, + 'EDPnet' => 32855, + 'Engie Electrabel' => 37616, + 'Epic Games Store' => 39027, + 'Facebook' => 22339, + 'Facebook Messenger' => 34851, + 'Facetime' => 34605, + 'Fifa' => 36906, + 'Fintro' => 37617, + 'Fluvius' => 37615, + 'Fortnite' => 36696, + 'Ghost Recon' => 39001, + 'Gmail' => 32374, + 'Google' => 32343, + 'Google Hangouts' => 32395, + 'Google Play' => 32371, + 'Gran Turismo' => 36913, + 'Grindr' => 38743, + 'GTA 5' => 35500, + 'Guild Wars 2' => 36474, + 'iCloud' => 22363, + 'iMessage' => 32463, + 'ING' => 22342, + 'Instagram' => 34286, + 'Isabel' => 34004, + 'Itsme' => 37454, + 'iTunes' => 32484, + 'Jim Mobile' => 37618, + 'KBC' => 32544, + 'Kik' => 32524, + 'Kraken' => 36828, + 'League of Legends' => 38631, + 'Lebara' => 32461, + 'LinkedIn' => 32534, + 'Lycamobile' => 32462, + 'Mobile Vikings' => 32854, + 'Moneyou' => 32488, + 'Multisafepay' => 34878, + 'Nest' => 38517, + 'Netflix' => 34629, + 'Numéricable' => 32856, + 'Office 365' => 36409, + 'OneDrive' => 35410, + 'Orange' => 10208, + 'Origin' => 36888, + 'Outlook' => 32375, + 'Overwatch' => 36383, + 'OVH' => 36746, + 'Paypal' => 32354, + 'Paysafecard' => 32485, + 'Play Sports' => 37582, + 'Player Unknown\'s Battlegrounds' => 36568, + 'Playstation Network' => 32339, + 'Pokémon Go' => 35736, + 'Proximus' => 10206, + 'Rainbow Six' => 36180, + 'Reddit' => 37474, + 'Roblox' => 38757, + 'Rocket League' => 35978, + 'Runescape' => 38654, + 'Salesforce' => 32349, + 'Scarlet' => 32435, + 'Simyo' => 32387, + 'Skype' => 32357, + 'Smartschool' => 37620, + 'Snapchat' => 32520, + 'Sofort Banking' => 32482, + 'Spotify' => 32336, + 'Steam' => 34278, + 'Strava' => 38161, + 'Teamviewer' => 34907, + 'Telegram' => 35971, + 'Telenet' => 10196, + 'Tinder' => 35499, + 'TuneIn' => 38759, + 'TV Vlaanderen' => 22364, + 'Tweakbox' => 38786, + 'Twitch' => 36542, + 'Twitter' => 22355, + 'Unibet' => 38830, + 'Uplay PC' => 35614, + 'Viber' => 32505, + 'Voo' => 32853, + 'VTM' => 38394, + 'Waze' => 36657, + 'WeTransfer' => 32523, + 'Whatsapp' => 32333, + 'Wikipedia' => 32425, + 'Wordfeud' => 22358, + 'Xbox Live' => 32481, + 'Yahoo Mail' => 34840, + 'Yellowbrick' => 37609, + 'Yeloplay' => 37359, + 'YouTube' => 32338, + 'Z1 Battle Royale' => 37258, + ), + 'Australia' => array( + '2k' => 36402, + '4chan' => 38290, + 'AAPT telecommunications' => 35849, + 'ABC' => 37712, + 'Activ8me' => 36814, + 'Adam Internet' => 33877, + 'Adelaide Bank' => 36729, + 'Adobe Creative Cloud' => 34553, + 'Airbnb' => 36403, + 'Alexa' => 36922, + 'Amaysim' => 35654, + 'Amazon' => 36404, + 'Amazon Prime Video' => 36968, + 'Amazon Web Services' => 34093, + 'American Express' => 38173, + 'Amino Apps' => 39045, + 'Amnet' => 33878, + 'Anthem' => 38176, + 'ANZ' => 33364, + 'Apex Legends' => 38125, + 'App Store' => 35577, + 'Apple Music' => 35243, + 'Apple Store' => 34455, + 'ARK: Survival Evolved' => 38746, + 'Assassin\'s Creed' => 35008, + 'AusBBS' => 36812, + 'Aussie Broadband' => 37219, + 'Australia Post' => 37052, + 'Bank Australia' => 38682, + 'Bank of Melbourne' => 35356, + 'Bank of Queensland' => 37458, + 'Bank SA' => 35354, + 'Bankwest' => 34972, + 'Battlefield' => 37468, + 'Belong' => 37179, + 'Bendigo Bank' => 37715, + 'BigPond' => 33993, + 'Binance' => 36878, + 'Bing' => 32874, + 'Blizzard Battle.net' => 35053, + 'Blogger' => 32875, + 'Boom Beach' => 36871, + 'Box' => 32876, + 'Brawl Stars' => 38816, + 'Bumble' => 36809, + 'Call of Duty' => 36405, + 'Candy Crush' => 35092, + 'Centrelink' => 37549, + 'Centurylink' => 34131, + 'Citibank' => 36507, + 'Clash of Clans' => 37302, + 'Clash Royale' => 38953, + 'Cloudflare' => 32877, + 'ClubTelco' => 34792, + 'Coinbase' => 36802, + 'Coinspot' => 36927, + 'Commander' => 37714, + 'Commonwealth Bank' => 33362, + 'Counter-strike' => 35059, + 'Crackle' => 35112, + 'Craigslist' => 32878, + 'Crunchyroll' => 36717, + 'Dead By Daylight' => 37415, + 'Deezer' => 33833, + 'Deliveroo' => 38197, + 'Destiny' => 34894, + 'DFP' => 35002, + 'Discord' => 36022, + 'Dodo' => 34003, + 'Doordash' => 39006, + 'Dota 2' => 35405, + 'Dropbox' => 32879, + 'EA' => 34509, + 'eBay' => 32880, + 'Eftel' => 35553, + 'Elite: Dangerous' => 37104, + 'Escape from Tarkov' => 38626, + 'ESPN' => 38387, + 'Etsy' => 37481, + 'Exchange Online' => 34545, + 'Exetel' => 34478, + 'Facebook' => 32881, + 'Facebook Messenger' => 32882, + 'Facetime' => 34601, + 'Fallout' => 35432, + 'Far Cry' => 37190, + 'Fifa' => 35473, + 'Fitbit' => 38358, + 'Flickr' => 32883, + 'Fonality' => 34313, + 'For Honor' => 35989, + 'Fortnite' => 36622, + 'Foxtel' => 33355, + 'Funimation' => 38583, + 'Game of war' => 35416, + 'Gears of War' => 38894, + 'Ghost Recon' => 36008, + 'GitHub' => 36529, + 'Gmail' => 32885, + 'Go Daddy' => 36619, + 'Google' => 32886, + 'Google Drive' => 34274, + 'Google Hangouts' => 32887, + 'Google Home' => 37343, + 'Google Play' => 32888, + 'Gran Turismo' => 36875, + 'Grindr' => 35834, + 'GTA 5' => 34755, + 'Guild Wars 2' => 36408, + 'Gumtree' => 33360, + 'Halo' => 35449, + 'Hay Day' => 34786, + 'Hayu' => 38366, + 'Hearthstone' => 38660, + 'Heronet' => 35949, + 'Hipchat' => 34867, + 'Hootsuite' => 32889, + 'iCloud' => 32890, + 'iiNet' => 33555, + 'iMessage' => 32891, + 'Imgur' => 32892, + 'Instagram' => 32893, + 'Internode' => 34477, + 'iPrimus' => 33876, + 'iTunes' => 32894, + 'Kik' => 32895, + 'Kraken' => 36849, + 'Ladbrokes' => 37640, + 'LastPass' => 34776, + 'League of Legends' => 35049, + 'LinkedIn' => 32896, + 'Mail.com' => 34799, + 'Mailbox' => 34834, + 'Mate Communicate' => 36813, + 'McDonalds app' => 37525, + 'ME Bank' => 34973, + 'Microsoft Azure' => 32917, + 'Microsoft Teams' => 38694, + 'Minecraft' => 32897, + 'My Fitness Pal' => 37633, + 'My Republic' => 35982, + 'MyGov' => 37550, + 'MyNetFone' => 35481, + 'myob' => 36343, + 'NAB' => 33365, + 'National Broadband Network, NBN' => 35992, + 'NBA 2k' => 37736, + 'Netflix' => 35177, + 'Netregistry' => 36060, + 'Netspeed' => 34492, + 'Nine' => 37000, + 'Nintendo eShop' => 34102, + 'Nintendo Network' => 35517, + 'Nintendo Switch Online' => 37243, + 'No Man\'s Sky' => 37404, + 'Office 365' => 34543, + 'OkCupid' => 38489, + 'OneDrive' => 32904, + 'Optus' => 33356, + 'Origin' => 35091, + 'Outlook' => 32899, + 'Overwatch' => 35683, + 'Paladins' => 37656, + 'Pandora' => 33343, + 'Panthur' => 36346, + 'Path of Exile' => 36498, + 'Paypal' => 35607, + 'Photobucket' => 32901, + 'Pinterest' => 32902, + 'Player Unknown\'s Battlegrounds' => 36356, + 'Playstation Network' => 34842, + 'PlentyOfFish' => 37416, + 'Pokémon Go' => 35732, + 'Project Online' => 34542, + 'Quickbooks Online' => 38220, + 'Rabobank' => 34974, + 'Rabodirect' => 34975, + 'Rainbow Six' => 35478, + 'Red Dead Redemption' => 37740, + 'Reddit' => 34843, + 'Roblox' => 36832, + 'Rocket League' => 35497, + 'Runescape' => 35106, + 'Salesforce' => 32903, + 'Sarahah' => 36374, + 'SBS' => 34703, + 'Sea of Thieves' => 37115, + 'Sharepoint Online' => 34541, + 'Skype' => 32905, + 'Skype for Business' => 34544, + 'Slack' => 35937, + 'Slideshare' => 32906, + 'Smite' => 35406, + 'Snapchat' => 32907, + 'Soundcloud' => 37230, + 'Spintel' => 35962, + 'Sportsbet' => 37713, + 'Spotify' => 33225, + 'St. George Bank' => 35353, + 'Stan' => 35503, + 'Star Wars Battlefront' => 35552, + 'Steam' => 34114, + 'Steep' => 37922, + 'Summoners War' => 37418, + 'Suncorp Bank' => 34432, + 'Sure Telecom' => 34394, + 'Tango' => 33742, + 'Teamviewer' => 34617, + 'Telegram' => 34220, + 'Telstra' => 33354, + 'The Division' => 35572, + 'The elder scrolls online' => 36554, + 'The Simpsons Tapped out' => 38166, + 'Think Mobile' => 34527, + 'Tiktok' => 39061, + 'Tinder' => 34241, + 'TPG Telecom' => 33359, + 'Tumblr' => 32910, + 'TuneIn' => 38761, + 'Tweakbox' => 38346, + 'Twitch' => 35026, + 'Twitter' => 32911, + 'Uber' => 37766, + 'Uber Eats' => 38272, + 'Uberglobal' => 35669, + 'Udemy' => 37719, + 'Uplay PC' => 36211, + 'V4 Telecom' => 37357, + 'Vaya' => 34518, + 'Viber' => 32912, + 'Vimeo' => 32913, + 'Virgin Mobile' => 34516, + 'Vocus' => 37711, + 'Vodafone' => 33357, + 'War Thunder' => 38361, + 'Warframe' => 36495, + 'Wattpad' => 34694, + 'Waze' => 33405, + 'Webex' => 34162, + 'Weebly' => 34911, + 'Westnet' => 35163, + 'Westpac' => 33363, + 'WeTransfer' => 32914, + 'Whatsapp' => 32915, + 'Wikipedia' => 32916, + 'Wish' => 39042, + 'Wix' => 37255, + 'Wordpress.com' => 32918, + 'World of Tanks' => 37191, + 'World of Warcraft' => 35054, + 'WWE Network' => 38722, + 'Xbox Live' => 34283, + 'Xero' => 36177, + 'Yahoo' => 32919, + 'Yahoo Mail' => 32920, + 'Yahoo Messenger' => 32921, + 'Yelp' => 32922, + 'Youtube' => 32923, + 'Youtube Music' => 37590, + 'Z1 Battle Royale' => 35494, + 'Zettanet' => 35655, + 'ZoHo' => 37551, + ), + 'Canada' => array( + '2k' => 36723, + 'Acanac' => 34107, + 'Access' => 33069, + 'Aeroplan' => 35789, + 'Air Canada' => 37029, + 'Air Miles' => 35788, + 'Airbnb' => 37423, + 'Alaska Airlines' => 32926, + 'Alexa' => 37067, + 'Allegiant Air' => 32927, + 'Allstream' => 34001, + 'Altima Telecom' => 37247, + 'Amazon' => 32928, + 'Amazon Prime Music' => 38907, + 'Amazon Prime Video' => 37393, + 'Amazon Web Services' => 32929, + 'American Airlines' => 32930, + 'American Express' => 38172, + 'Amino Apps' => 38716, + 'Anthem' => 38056, + 'Anydesk' => 37488, + 'Apex Legends' => 38113, + 'App Store' => 35576, + 'Apple Music' => 35244, + 'Apple Store' => 34456, + 'ARK: Survival Evolved' => 38747, + 'Assassin\'s Creed' => 35007, + 'BabyTEL' => 35360, + 'Battlefield' => 36923, + 'BC Hydro' => 35806, + 'Beanfield' => 36663, + 'beIN' => 38788, + 'Bell' => 32936, + 'Bell Aliant' => 32937, + 'Bet365' => 39064, + 'Binance' => 36876, + 'Bing' => 32938, + 'Black Desert Online' => 38829, + 'Blizzard Battle.net' => 34488, + 'Blogger' => 32940, + 'BMO' => 34525, + 'Boom Beach' => 36558, + 'Box' => 32941, + 'Brama Telecom' => 34146, + 'Brawl Stars' => 38833, + 'Bumble' => 36330, + 'Call of Duty' => 34149, + 'Candy Crush' => 35093, + 'Capital One' => 36410, + 'Carry Telecom' => 37695, + 'CBC' => 34267, + 'Centurylink' => 35627, + 'Chatr' => 34005, + 'CIBC' => 34526, + 'CIK Telecom' => 34428, + 'Clash of Clans' => 34445, + 'Clash Royale' => 37523, + 'Cloudflare' => 32952, + 'CNN' => 37372, + 'Cogeco' => 32953, + 'Cogent' => 35556, + 'Coinbase' => 36800, + 'Colbanet' => 37542, + 'CommStream' => 36028, + 'Comwave' => 36641, + 'Counter-strike' => 35056, + 'Crackle' => 35111, + 'Craigslist' => 32956, + 'Crave TV' => 35621, + 'Crunchyroll' => 36716, + 'Dark Souls' => 36557, + 'DayZ' => 39007, + 'Dazn' => 36510, + 'Dead By Daylight' => 36595, + 'Delta Air Lines' => 32958, + 'Destiny' => 34892, + 'DFP' => 35001, + 'Diablo' => 39071, + 'Discord' => 36411, + 'Distributel' => 33870, + 'Doordash' => 38385, + 'Dota 2' => 35404, + 'Dropbox' => 32961, + 'EA' => 34504, + 'EA Sports UFC' => 36552, + 'Eastlink' => 33414, + 'eBay' => 32964, + 'Ebox' => 35555, + 'Ecobee' => 38021, + 'Elite: Dangerous' => 37103, + 'Epic Games Store' => 38767, + 'Equitable Bank' => 36731, + 'Escape from Tarkov' => 37975, + 'Etsy' => 38265, + 'Exchange Online' => 34546, + 'Execulink' => 34942, + 'Expedia' => 37401, + 'Facebook' => 32965, + 'Facebook Messenger' => 32966, + 'Facetime' => 34595, + 'Fallout' => 37663, + 'FedEx' => 36500, + 'Fido' => 34000, + 'Fifa' => 35472, + 'Fitbit' => 38359, + 'Flickr' => 32967, + 'For Honor' => 35986, + 'Fortnite' => 36623, + 'Forza' => 38836, + 'Fox News' => 37665, + 'Freedom Mobile' => 33869, + 'Friday the 13th The Game' => 37562, + 'Funimation' => 37744, + 'Game of war' => 35415, + 'Garmin Connect' => 38540, + 'Gears of War' => 35938, + 'Ghost Recon' => 37772, + 'GitHub' => 32970, + 'Gmail' => 32971, + 'Go Daddy' => 34943, + 'GO Transit' => 32972, + 'Google' => 32973, + 'Google Calendar' => 38599, + 'Google Cloud' => 38537, + 'Google Drive' => 34272, + 'Google Hangouts' => 32974, + 'Google Home' => 36141, + 'Google Play' => 32975, + 'GoToMeeting' => 36504, + 'Gran Turismo' => 36679, + 'Grindr' => 35835, + 'GTA 5' => 34756, + 'Guild Wars 2' => 36406, + 'Halo' => 35450, + 'Harry Potter: Wizards Unite' => 38687, + 'Hay Day' => 34789, + 'Hayu' => 38789, + 'Hearthstone' => 38289, + 'Hipchat' => 34868, + 'Hootsuite' => 32977, + 'HQ Trivia' => 37027, + 'HSBC' => 39048, + 'Hue' => 37814, + 'HughesNet' => 32978, + 'iCloud' => 32979, + 'iMessage' => 33249, + 'Imgur' => 32981, + 'IMVU' => 37472, + 'Indeed' => 38782, + 'Instagram' => 32982, + 'Interac' => 39049, + 'iTunes' => 32983, + 'JetBlue Airways' => 32984, + 'Jira' => 38545, + 'Juno' => 32985, + 'Kijiji' => 34303, + 'Kik' => 32986, + 'Koodo' => 34002, + 'Kraken' => 36750, + 'LastPass' => 36785, + 'League of Legends' => 35047, + 'Lightspeed' => 37066, + 'LinkedIn' => 32987, + 'Madden' => 38459, + 'Mail.com' => 34801, + 'Mailbox' => 34837, + 'McDonalds app' => 37642, + 'MCSNet' => 35889, + 'Metro Loop' => 37646, + 'Microsoft Azure' => 33057, + 'Minecraft' => 32996, + 'Mixer' => 38769, + 'MLB The Show' => 36989, + 'MLB TV' => 37189, + 'Montréal Metro' => 32997, + 'Mordhau' => 38734, + 'MTS' => 33868, + 'My Fitness Pal' => 37632, + 'NBA 2k' => 37722, + 'Nest' => 35191, + 'Netflix' => 32998, + 'NetZero' => 32999, + 'Neverwinter' => 35766, + 'Nintendo eShop' => 34101, + 'Nintendo Network' => 35518, + 'No Man\'s Sky' => 38779, + 'NorthernTel' => 34636, + 'Northwestel' => 35104, + 'Office 365' => 34548, + 'OkCupid' => 36678, + 'OneDrive' => 33020, + 'Oricom Internet' => 35829, + 'Origin' => 36584, + 'Outlook' => 33005, + 'Overwatch' => 35682, + 'Paladins' => 37664, + 'Path of Exile' => 36481, + 'Paypal' => 33010, + 'PC Optimum' => 37216, + 'Peer 1' => 34824, + 'Photobucket' => 33011, + 'Pinterest' => 33012, + 'Piper' => 38323, + 'Player Unknown\'s Battlegrounds' => 36337, + 'Playstation Network' => 33013, + 'PlentyOfFish' => 35798, + 'Pokémon Go' => 35734, + 'Pokerstars' => 38174, + 'Primus' => 33872, + 'Qtrade Financial Group' => 36025, + 'Quickbooks Online' => 37607, + 'Quizup' => 34297, + 'Rabb.it' => 37974, + 'Rainbow Six' => 35477, + 'RBC' => 34521, + 'Red Dead Redemption' => 37742, + 'Reddit' => 34845, + 'Roblox' => 35785, + 'Rocket League' => 35498, + 'Rogers' => 33015, + 'Runescape' => 35105, + 'Salesforce' => 33016, + 'Sarahah' => 36514, + 'Sasktel' => 33871, + 'Scotiabank' => 34523, + 'Sea of Thieves' => 37111, + 'Sharepoint Online' => 34550, + 'Shaw' => 33551, + 'Shopify' => 35863, + 'Signal' => 36328, + 'Simplii' => 37541, + 'SiriusXM' => 38561, + 'SkipTheDishes' => 38322, + 'Skype' => 33021, + 'Skype for Business' => 34547, + 'Slack' => 35935, + 'Slideshare' => 33023, + 'Smartsheet' => 38724, + 'Smite' => 37026, + 'Snapchat' => 33024, + 'Soundcloud' => 37229, + 'Sourceforge' => 33025, + 'Spotify' => 33028, + 'Star Wars Battlefront' => 35550, + 'Start Communications' => 34426, + 'Steam' => 33030, + 'Steep' => 37923, + 'Strava' => 38745, + 'Summoners War' => 37422, + 'Tangerine' => 37694, + 'Tango' => 33741, + 'Tbaytel' => 34612, + 'TD Canada Trust' => 34522, + 'Teamviewer' => 34618, + 'TekSavvy' => 33867, + 'Télébec' => 34110, + 'Telegram' => 34228, + 'Telnet' => 34158, + 'Telus' => 33034, + 'TeraGo' => 34427, + 'Tesla' => 38835, + 'The Division' => 35571, + 'The elder scrolls online' => 36399, + 'The Simpsons Tapped out' => 35109, + 'The Weather Channel' => 38837, + 'Ticketmaster' => 39008, + 'Tiktok' => 38727, + 'Tinder' => 34239, + 'Toronto Transit Commission' => 33036, + 'Translink' => 33039, + 'Trello' => 39066, + 'Trove' => 38825, + 'Tumblr' => 33040, + 'TuneIn' => 36037, + 'TurboTax' => 38213, + 'Tweakbox' => 38343, + 'Twitch' => 35023, + 'Twitter' => 33042, + 'Uber' => 37765, + 'Uber Eats' => 38022, + 'Udemy' => 37718, + 'United Airlines' => 33044, + 'Uplay PC' => 34688, + 'UPS' => 36831, + 'Vancity' => 37570, + 'Velcom' => 36978, + 'Viber' => 33348, + 'Vidéotron' => 33050, + 'Vimeo' => 33051, + 'Virgin Mobile' => 34096, + 'Visa' => 38693, + 'VMedia' => 34265, + 'Warface' => 38777, + 'Warframe' => 36370, + 'Wattpad' => 34695, + 'Waveapps' => 35960, + 'Waze' => 33406, + 'Webex' => 34160, + 'Weight Watchers' => 35664, + 'WestJet' => 35648, + 'WeTransfer' => 33054, + 'Whatsapp' => 33055, + 'Whisper' => 34625, + 'Wiband' => 34771, + 'Wikipedia' => 33056, + 'Wish' => 39041, + 'Wisp' => 37218, + 'Wordpress.com' => 33059, + 'World of Tanks' => 35527, + 'World of Warcraft' => 34264, + 'WWE Network' => 38717, + 'Xbox Live' => 33061, + 'Xplornet' => 34270, + 'Yahoo' => 33063, + 'Yahoo Mail' => 33064, + 'Yahoo Messenger' => 33065, + 'Yak' => 34269, + 'Yelp' => 33066, + 'Youtube' => 33067, + 'Youtube Music' => 37588, + 'Yubo' => 38961, + 'Z1 Battle Royale' => 35491, + 'ZoHo' => 36038, + 'Zoom' => 37947, + 'Zynga' => 33068, + ), + 'Hong Kong' => array( + '3 (Three)' => 36202, + 'Apex Legends' => 38178, + 'App Store' => 37734, + 'Binance' => 37023, + 'Blizzard Battle.net' => 36186, + 'China Mobile' => 36199, + 'Cloudflare' => 38641, + 'Counter-strike' => 38725, + 'CSL' => 36200, + 'Discord' => 38608, + 'EA' => 36700, + 'eBay' => 36207, + 'Facebook' => 36185, + 'Fifa' => 37604, + 'For Honor' => 36187, + 'Ghost Recon' => 38990, + 'Gmail' => 36188, + 'Google' => 36210, + 'Google Drive' => 38264, + 'Google Play' => 38526, + 'GTA 5' => 37279, + 'Hong Kong Broadband Network' => 36204, + 'iCloud' => 38842, + 'Instagram' => 36392, + 'Kraken' => 36984, + 'Netflix' => 36213, + 'Netvigator' => 36203, + 'Office 365' => 37172, + 'Origin' => 38396, + 'Outlook' => 36189, + 'Overwatch' => 36190, + 'PCCW' => 36205, + 'Player Unknown\'s Battlegrounds' => 36617, + 'Playstation Network' => 36191, + 'Pokémon Go' => 36192, + 'Rainbow Six' => 36193, + 'Reddit' => 37479, + 'Skype' => 36194, + 'Smartone' => 36198, + 'Snapchat' => 36208, + 'Steam' => 38650, + 'Telegram' => 36195, + 'Three Home Broadband' => 36206, + 'Tinder' => 36196, + 'TuneIn' => 36036, + 'Twitter' => 38671, + 'Uplay PC' => 36212, + 'Whatsapp' => 36197, + 'Yahoo Mail' => 36769, + 'Youtube' => 36209, + ), + 'Ireland' => array( + '3 (Three)' => 34214, + 'AIB (Allied Irish Banks)' => 34209, + 'Amazon' => 34165, + 'Apex Legends' => 38133, + 'App Store' => 38557, + 'Apple Store' => 34460, + 'Bank of Ireland' => 37754, + 'Battlefield' => 38451, + 'Binance' => 36931, + 'Bing' => 34166, + 'Boom Beach' => 35153, + 'Call of Duty' => 36709, + 'Counter-strike' => 38233, + 'Craigslist' => 34167, + 'Crunchyroll' => 38094, + 'Dead By Daylight' => 37444, + 'Deezer' => 34168, + 'Destiny' => 38615, + 'Digiweb' => 34875, + 'Discord' => 37390, + 'DoneDeal' => 34208, + 'EA' => 36413, + 'eBay' => 34169, + 'Eir' => 34210, + 'eMobile' => 34211, + 'Facebook' => 34170, + 'Facebook Messenger' => 34171, + 'Facetime' => 34584, + 'Fifa' => 36907, + 'Fortnite' => 36692, + 'Ghost Recon' => 38992, + 'Gmail' => 34172, + 'Google' => 34173, + 'Google Hangouts' => 34174, + 'Google Play' => 34175, + 'Gran Turismo' => 36949, + 'Grindr' => 36755, + 'GTA 5' => 37275, + 'Hootsuite' => 34176, + 'iCloud' => 34177, + 'Imagine' => 34425, + 'iMessage' => 34178, + 'Imgur' => 34179, + 'Instagram' => 34180, + 'iTunes' => 34181, + 'Kik' => 34182, + 'Kraken' => 36850, + 'Ladbrokes' => 37469, + 'LinkedIn' => 34183, + 'Magnet' => 34424, + 'Meteor' => 34213, + 'My Fitness Pal' => 37634, + 'Nest' => 35193, + 'Netflix' => 34184, + 'Now TV' => 38403, + 'O2' => 34206, + 'Office 365' => 35441, + 'Origin' => 36890, + 'Outlook' => 34185, + 'Overwatch' => 36484, + 'Paddy Power' => 38360, + 'Pinterest' => 34186, + 'Playstation Network' => 34187, + 'PlentyOfFish' => 37417, + 'Pokémon Go' => 35758, + 'Rabodirect' => 34979, + 'Rainbow Six' => 36414, + 'Red Dead Redemption' => 38288, + 'Reddit' => 36826, + 'Roblox' => 38756, + 'Rocket League' => 36670, + 'Ryanair' => 37253, + 'Sky' => 34212, + 'Skype' => 37018, + 'Sleepless' => 38314, + 'Snapchat' => 34188, + 'Spotify' => 34189, + 'Steam' => 34190, + 'Strava' => 38643, + 'Teamviewer' => 37631, + 'Telegram' => 37226, + 'Tinder' => 34864, + 'Tumblr' => 34191, + 'TuneIn' => 38760, + 'Twitch' => 36538, + 'Twitter' => 34192, + 'Ulster Bank' => 36070, + 'Viber' => 34193, + 'Vimeo' => 34194, + 'Virgin Media' => 34207, + 'Vodafone' => 34196, + 'Wattpad' => 34699, + 'Waze' => 34197, + 'Webex' => 34198, + 'Whatsapp' => 34199, + 'Wikipedia' => 34200, + 'Xbox Live' => 34201, + 'Yahoo' => 34202, + 'Yahoo Mail' => 34203, + 'Yahoo Messenger' => 34204, + 'Youtube' => 34205, + 'Youtube Music' => 37589, + 'Z1 Battle Royale' => 37261, + ), + 'Danmark' => array( + '3 (Tre)' => 33694, + 'Amazon' => 33651, + 'Anthem' => 38212, + 'Apex Legends' => 38128, + 'App Store' => 38554, + 'Apple Store' => 34452, + 'Battlefield' => 37097, + 'Bet365' => 38813, + 'Bibob' => 33841, + 'Binance' => 36930, + 'Blizzard Battle.net' => 36162, + 'Call of Duty' => 36707, + 'CBB Mobil' => 33840, + 'Counter-strike' => 36171, + 'Crunchyroll' => 36721, + 'Danske Bank' => 33687, + 'DBA' => 33700, + 'Dead By Daylight' => 37427, + 'Deezer' => 33835, + 'Destiny' => 36593, + 'Discord' => 36682, + 'DMI' => 36121, + 'Dota 2' => 36398, + 'EA' => 35496, + 'eBay' => 34862, + 'EnergiMidt' => 34435, + 'Epic Games Store' => 39025, + 'Ewii' => 34436, + 'Facebook' => 33652, + 'Facebook Messenger' => 33653, + 'Faceit' => 38542, + 'Facetime' => 34590, + 'Fifa' => 36621, + 'For Honor' => 36163, + 'Fortnite' => 36690, + 'Fullrate' => 34433, + 'Ghost Recon' => 39002, + 'Gmail' => 33654, + 'Google' => 33655, + 'Google Drive' => 36606, + 'Google Hangouts' => 33656, + 'Google Play' => 33657, + 'Gran Turismo' => 36915, + 'GTA 5' => 36170, + 'Guild Wars 2' => 36469, + 'HBO Nordic' => 35605, + 'iCloud' => 33658, + 'iMessage' => 33659, + 'Instagram' => 33660, + 'iTunes' => 33661, + 'Kik' => 33705, + 'Kraken' => 36851, + 'Kviknet' => 38016, + 'League of Legends' => 36166, + 'LinkedIn' => 33701, + 'Minecraft' => 37282, + 'Net 1' => 33725, + 'Netflix' => 33689, + 'Nordea' => 33688, + 'Office 365' => 35440, + 'OneDrive' => 36867, + 'Origin' => 36894, + 'Outlook' => 33662, + 'Overwatch' => 36165, + 'Path of Exile' => 36482, + 'Playerunknown\'s Battlegrounds' => 36334, + 'Playstation Network' => 33663, + 'Pokémon Go' => 35753, + 'Rainbow Six' => 36161, + 'Realm Royale' => 37306, + 'Red Dead Redemption' => 38306, + 'Reddit' => 36824, + 'Roblox' => 36612, + 'Rocket League' => 35977, + 'Sea of Thieves' => 37122, + 'Skype' => 33686, + 'Snapchat' => 33696, + 'Spotify' => 33697, + 'Steam' => 34277, + 'Stofa' => 34434, + 'TDC' => 33691, + 'Teamviewer' => 35693, + 'Telegram' => 37181, + 'Telenor' => 33692, + 'Telia' => 33693, + 'Tinder' => 34861, + 'Twitch' => 35508, + 'Twitter' => 33664, + 'Uplay PC' => 35610, + 'Viaplay' => 37292, + 'Viber' => 33698, + 'Warframe' => 36703, + 'Whatsapp' => 33703, + 'Wikipedia' => 33665, + 'Wordfeud' => 33702, + 'World of Warcraft' => 36168, + 'World of Warships' => 38013, + 'Xbox Live' => 33666, + 'Yahoo Mail' => 37043, + 'Youmusic' => 33699, + 'Yousee' => 33695, + 'Youtube' => 33667, + 'Z1 Battle Royale' => 37265, + ), + 'Sverige' => array( + '3 (Tre)' => 33722, + 'A3' => 38249, + 'Amazon' => 33668, + 'Anthem' => 38190, + 'Apex Legends' => 38115, + 'App Store' => 38101, + 'Apple Store' => 34450, + 'Bahnhof' => 34417, + 'BankID' => 33845, + 'Battlefield' => 37093, + 'Bet365' => 38812, + 'Binance' => 36933, + 'Blizzard Battle.net' => 34484, + 'Blocket' => 33716, + 'Boxer' => 37572, + 'Bredband2' => 34418, + 'Bredbandsbolaget' => 33843, + 'Bredbandsson' => 36049, + 'Call of Duty' => 35539, + 'Com Hem' => 34416, + 'Counter-strike' => 36172, + 'Crunchyroll' => 36719, + 'Dead By Daylight' => 36598, + 'Destiny' => 35510, + 'Discord' => 36764, + 'Dota 2' => 35876, + 'EA' => 35509, + 'eBay' => 34863, + 'Epic Games Store' => 39023, + 'Escape from Tarkov' => 38107, + 'Eurosport Player' => 36613, + 'Facebook' => 33669, + 'Facebook Messenger' => 33670, + 'Faceit' => 39039, + 'Facetime' => 34589, + 'Fifa' => 36909, + 'For Honor' => 35998, + 'Fortnite' => 36685, + 'Ghost Recon' => 39003, + 'Glocalnet' => 33842, + 'Gmail' => 33671, + 'Google' => 33672, + 'Google Drive' => 36604, + 'Google Hangouts' => 33673, + 'Google Play' => 33674, + 'Gran Turismo' => 36914, + 'Grindr' => 38739, + 'GTA 5' => 35528, + 'Guild Wars 2' => 36466, + 'Halebop' => 33726, + 'Handelsbanken' => 33718, + 'Hay Day' => 38214, + 'HBO Nordic' => 35606, + 'Hearthstone' => 38659, + 'Hue' => 37816, + 'iCloud' => 33675, + 'Ikano Bank' => 36578, + 'iMessage' => 33676, + 'Instagram' => 33677, + 'iTunes' => 33678, + 'Kik' => 33704, + 'Kraken' => 36829, + 'League of Legends' => 36167, + 'LinkedIn' => 33714, + 'Minecraft' => 37281, + 'Net 1' => 33724, + 'Netflix' => 33706, + 'Nordea' => 33717, + 'Office 365' => 35439, + 'OneDrive' => 36869, + 'Origin' => 36898, + 'Outlook' => 33679, + 'Overwatch' => 36150, + 'Path of Exile' => 36480, + 'Playerunknown\'s Battlegrounds' => 36333, + 'Playstation Network' => 33707, + 'Pokémon Go' => 35749, + 'Rainbow Six' => 36148, + 'Realm Royale' => 37307, + 'Red Dead Redemption' => 38285, + 'Reddit' => 35883, + 'Riksnet' => 37486, + 'Roblox' => 36611, + 'Rocket League' => 35487, + 'Sea of Thieves' => 37114, + 'SEB' => 33719, + 'SF Anytime' => 37573, + 'SkandiaBanken' => 34021, + 'Skype' => 33708, + 'Slack' => 37495, + 'Snapchat' => 33709, + 'Soundcloud' => 37228, + 'Sparbanken Öresund' => 34310, + 'Spotify' => 33838, + 'Steam' => 34135, + 'Swedbank' => 33713, + 'Swish' => 35777, + 'Teamviewer' => 35692, + 'Tele2' => 33721, + 'Telegram' => 35969, + 'Telenor' => 33723, + 'Telia' => 33720, + 'Telldus' => 36653, + 'The Elder Scrolls Online' => 36033, + 'Tinder' => 36458, + 'Tradera' => 33715, + 'Tumblr' => 36713, + 'Tweakbox' => 38905, + 'Twitch' => 35507, + 'Twitter' => 33710, + 'Uplay PC' => 35609, + 'Viaplay' => 37291, + 'Viber' => 37502, + 'Warframe' => 36701, + 'Whatsapp' => 33711, + 'Wikipedia' => 33682, + 'Wordfeud' => 33712, + 'World of Tanks' => 35488, + 'World of Warcraft' => 36169, + 'World of Warships' => 38011, + 'Xbox Live' => 33683, + 'Yahoo Mail' => 37044, + 'Youtube' => 33684, + 'Z1 Battle Royale' => 35493, + ), + 'Italia' => array( + '3 Italia' => 33154, + 'Airbnb' => 37345, + 'Aircomm' => 36015, + 'Alexa' => 38031, + 'AlternatYva' => 37556, + 'Amazon' => 33174, + 'Amazon Prime Video' => 36975, + 'Anthem' => 38189, + 'Anydesk' => 37491, + 'Apex Legends' => 38119, + 'App Store' => 37733, + 'Apple Store' => 34468, + 'Aruba' => 37217, + 'Banco di Napoli' => 33181, + 'Battlefield' => 37095, + 'Betclic' => 39047, + 'Binance' => 36937, + 'Blizzard Battle.net' => 37092, + 'BNL' => 33180, + 'Brawl Stars' => 38821, + 'Bwin' => 35072, + 'Call of Duty' => 35537, + 'Clash of Clans' => 34361, + 'Clash Royale' => 38956, + 'Cloudflare' => 38620, + 'Coinbase' => 36801, + 'Coopvoce' => 34921, + 'Counter-strike' => 36650, + 'Credito Emiliano - Credem' => 33182, + 'Crunchyroll' => 38095, + 'Dazn' => 37442, + 'Dead By Daylight' => 36627, + 'Deezer' => 33839, + 'Destiny' => 36590, + 'Discord' => 36767, + 'Dota 2' => 35878, + 'Dropbox' => 33175, + 'EA' => 34498, + 'EA Sports UFC' => 36553, + 'eBay' => 32816, + 'Elite: Dangerous' => 37774, + 'Eolo' => 37763, + 'Epic Games Store' => 39024, + 'Escape from Tarkov' => 39056, + 'Facebook' => 32812, + 'Facebook Messenger' => 32813, + 'Facetime' => 34598, + 'Fallout' => 37668, + 'Fastweb' => 33160, + 'Fifa' => 36910, + 'Fineco' => 33167, + 'Flickr' => 37949, + 'For Honor' => 35990, + 'Fortnite' => 36686, + 'Friday the 13th The Game' => 37564, + 'Ghost Recon' => 38999, + 'Gmail' => 32815, + 'Google' => 32805, + 'Google Drive' => 36607, + 'Google Hangouts' => 32806, + 'Google Play' => 32807, + 'Gran Turismo' => 36874, + 'Grindr' => 36757, + 'GTA5 ' => 35918, + 'Guild Wars 2' => 36472, + 'Ho' => 37408, + 'Hue' => 37813, + 'iCloud' => 33169, + 'Iliad' => 37214, + 'iMessage' => 33164, + 'Infinity' => 35972, + 'Infostrada' => 34711, + 'ING Direct' => 33168, + 'Instagram' => 33170, + 'Intesa Sanpaolo' => 33179, + 'iTunes' => 33159, + 'Kena Mobile' => 36364, + 'Kraken' => 36771, + 'League of Legends' => 37759, + 'Libero' => 33178, + 'LinkedIn' => 33177, + 'Linkem' => 34475, + 'Lottomatica' => 35068, + 'Lycamobile' => 38691, + 'Mc-link' => 34476, + 'Mediaset Premium' => 33162, + 'Mediaset TV Free' => 35973, + 'My Fitness Pal' => 37638, + 'Netflix' => 35568, + 'Neverwinter' => 36675, + 'NGI' => 34474, + 'Office 365' => 35443, + 'Onedrive' => 35411, + 'Origin' => 36897, + 'Outlook' => 33163, + 'Overwatch' => 36384, + 'Paddy Power' => 35069, + 'Paladins' => 36379, + 'Path of Exile' => 37726, + 'Paypal' => 33166, + 'Player Unknown\'s Battlegrounds' => 36567, + 'Playstation Network' => 32818, + 'Pokémon Go' => 35737, + 'Poste Italiane' => 37361, + 'PosteMobile' => 37360, + 'Quizduello' => 34299, + 'Rainbow Six' => 36045, + 'Red Dead Redemption' => 38284, + 'Reddit' => 37367, + 'Roblox' => 38916, + 'Rocket League' => 35979, + 'Ruzzle' => 33967, + 'Ryanair' => 37519, + 'Sea of Thieves' => 37121, + 'Sisal' => 35066, + 'Sky' => 33155, + 'Skype' => 32821, + 'Slack' => 37341, + 'SNAI' => 35067, + 'Snapchat' => 36446, + 'Spotify' => 33176, + 'Steam' => 34136, + 'Tango' => 33743, + 'Teamviewer' => 35455, + 'Telegram' => 34904, + 'The elder scrolls online' => 37327, + 'TIM' => 33158, + 'TimMusic' => 35913, + 'TimVision' => 35908, + 'Tinder' => 36549, + 'Tiscali' => 33161, + 'Tumblr' => 36712, + 'Tweakbox' => 38344, + 'Twitch' => 35604, + 'Twitter' => 32814, + 'UniCredit' => 33171, + 'Uplay PC' => 35613, + 'Viber' => 33403, + 'Virgilio' => 36459, + 'Vodafone' => 33156, + 'Warface' => 38765, + 'Warframe' => 36492, + 'WeBank' => 33173, + 'WeTransfer' => 36445, + 'Whatsapp' => 32820, + 'Wifi Trenitalia' => 35974, + 'Wikipedia' => 33172, + 'William Hill' => 35070, + 'Wind' => 33157, + 'World of Warships' => 38012, + 'Xbox Live' => 32819, + 'Yahoo' => 32809, + 'Yahoo Mail' => 32810, + 'Yahoo Messenger' => 32811, + 'Youtube' => 32808, + 'Z1 Battle Royale' => 37254, + 'ZoHo' => 37554, + ), + 'South Africa' => array( + 'ABSA' => 33599, + 'Afrihost' => 35660, + 'Amazon' => 33578, + 'Apex Legends' => 38157, + 'Apple Store' => 34458, + 'Axxess' => 35618, + 'Bidorbuy' => 33596, + 'Binance' => 36941, + 'Bing' => 33579, + 'Blizzard Battle.net' => 37661, + 'Call of Duty' => 34152, + 'Capitec' => 36966, + 'Cell C' => 33602, + 'Clash Royale' => 38946, + 'Cool Ideas' => 38326, + 'Counter-strike' => 36512, + 'Cybersmart' => 34619, + 'Dead By Daylight' => 37435, + 'Deezer' => 33834, + 'Destiny' => 38981, + 'DirecTV Now' => 35915, + 'Discord' => 38611, + 'Discovery' => 38334, + 'Dota 2' => 36428, + 'DSTv' => 33607, + 'EA' => 34507, + 'eBay' => 33581, + 'Eskom' => 38333, + 'Facebook' => 33582, + 'Facebook Messenger' => 37737, + 'Fifa' => 38436, + 'First National Bank (FNB)' => 33597, + 'Fortnite' => 36710, + 'Ghost Recon' => 38994, + 'Gmail' => 33583, + 'Google' => 33584, + 'Google Hangouts' => 33585, + 'Google Play' => 33586, + 'Gov.za' => 38328, + 'GTA 5' => 37273, + 'Guild Wars 2' => 36501, + 'Gumtree' => 33592, + 'iBurst' => 34620, + 'iCloud' => 33587, + 'Imaginet' => 38325, + 'Instagram' => 33588, + 'Internet Solutions' => 38332, + 'iTunes' => 33589, + 'Kik' => 33590, + 'Kraken' => 36985, + 'League of Legends' => 38633, + 'LinkedIn' => 33591, + 'Luno' => 37012, + 'Metrofibre' => 38335, + 'MTN' => 33601, + 'MWEB' => 33606, + 'Nedbank' => 35461, + 'Neotel' => 35426, + 'Netflix' => 36390, + 'Octotel' => 38327, + 'Office 365' => 35444, + 'OLX' => 33255, + 'Openserve' => 38331, + 'Origin' => 36886, + 'Outlook' => 33566, + 'Overwatch' => 36149, + 'Paypal' => 33567, + 'Pinterest' => 33568, + 'Player Unknown\'s Battlegrounds' => 36642, + 'Playstation Network' => 33569, + 'Pokémon Go' => 35756, + 'Rain' => 37397, + 'Rainbow Six' => 37738, + 'Reddit' => 38362, + 'Safricom' => 35139, + 'SARS' => 38336, + 'Seacom' => 38329, + 'Showmax' => 37149, + 'Skype' => 33570, + 'Snapchat' => 33571, + 'Standard Bank' => 33598, + 'Steam' => 34223, + 'Takealot' => 36777, + 'Teamviewer' => 37480, + 'Telegram' => 37184, + 'Telkom' => 33603, + 'The elder scrolls online' => 37325, + 'The Simpsons Tapped out' => 35903, + 'Tinder' => 37166, + 'Twitch' => 38702, + 'Twitter' => 33572, + 'Viber' => 33595, + 'Virgin Mobile' => 38324, + 'Vodacom' => 33600, + 'Vox' => 35368, + 'Vumatel' => 37660, + 'Warframe' => 37125, + 'Webafrica' => 38330, + 'WeChat' => 33594, + 'Whatsapp' => 33573, + 'Wikipedia' => 33574, + 'Xbox Live' => 34285, + 'Yahoo' => 33575, + 'Yahoo Mail' => 33576, + 'Youtube' => 33577, + ), + 'India' => array( + 'ACT' => 34764, + 'Aircel' => 33257, + 'Airtel' => 33233, + 'Alexa' => 36921, + 'AliExpress' => 37824, + 'Amazon' => 35118, + 'Amazon Prime Music' => 37583, + 'Amazon Prime Video' => 36974, + 'Amazon Web Services' => 38411, + 'Apex Legends' => 38180, + 'App Store' => 38556, + 'Apple Store' => 34459, + 'Bank of Baroda' => 37676, + 'Bank of India' => 33250, + 'Bharat Sanchar Nigam Limited (BSNL)' => 33232, + 'Binance' => 36932, + 'Bitbucket' => 36988, + 'Boom Beach' => 34782, + 'Brawl Stars' => 38822, + 'Call of Duty' => 34153, + 'Cherrinet' => 37677, + 'Clash of Clans' => 36872, + 'Clash Royale' => 38955, + 'Cloudflare' => 38652, + 'Counter-strike' => 38240, + 'Destiny' => 38989, + 'Discord' => 38106, + 'Dota 2' => 36393, + 'Dropbox' => 33237, + 'EA' => 34508, + 'eBay' => 32863, + 'Facebook' => 32860, + 'Facebook Messenger' => 33238, + 'Facetime' => 34596, + 'Fifa' => 38399, + 'Flipkart' => 33252, + 'Fortnite' => 36843, + 'GitHub' => 37606, + 'Gmail' => 32862, + 'Go Daddy' => 37499, + 'Google' => 32857, + 'Google Drive' => 38261, + 'Google Hangouts' => 32869, + 'Google Home' => 37344, + 'Google Play' => 33239, + 'GTA 5' => 37272, + 'Haptik' => 34762, + 'Hathway' => 37673, + 'Hay Day' => 34787, + 'HDFC Bank' => 33231, + 'ICICI Bank' => 37674, + 'iCloud' => 33240, + 'IDBI Bank' => 37678, + 'Idea Cellular' => 33234, + 'Idian Bank' => 37670, + 'iMessage' => 33248, + 'Instagram' => 33241, + 'IRCTC' => 37671, + 'iTunes' => 33230, + 'Jio' => 37460, + 'Kik' => 33351, + 'Line' => 33400, + 'LinkedIn' => 33242, + 'Mahanagar Telephone Nigam Limited (MTNL)' => 33258, + 'Microsoft Azure' => 36112, + 'MTS' => 33260, + 'Naukri' => 33253, + 'Netflix' => 37299, + 'Office 365' => 37174, + 'OLX' => 33593, + 'ooVoo' => 34084, + 'Origin' => 38378, + 'Outlook' => 33243, + 'Paypal' => 33244, + 'Paytm' => 33401, + 'Pinterest' => 37231, + 'Player Unknown\'s Battlegrounds' => 36643, + 'Playstation Network' => 32865, + 'Pokémon Go' => 35755, + 'Quora' => 37473, + 'Rainbow Six' => 36412, + 'Reddit' => 38061, + 'Reliance' => 33236, + 'Roblox' => 38921, + 'Salesforce' => 34734, + 'Sarahah' => 36513, + 'Skype' => 32868, + 'Snapchat' => 36741, + 'Spotify' => 37079, + 'Standard Chartered' => 33235, + 'State Bank of India (SBI)' => 33251, + 'Steam' => 35930, + 'Swiggy' => 37675, + 'Tango' => 33744, + 'Tata Docomo' => 33256, + 'Teamviewer' => 34346, + 'Telegram' => 36582, + 'Tiktok' => 38661, + 'Tinder' => 37167, + 'Tumblr' => 37641, + 'Twitch' => 38355, + 'Twitter' => 32861, + 'Uber Eats' => 38898, + 'Udemy' => 38389, + 'Uninor' => 33259, + 'Uplay PC' => 36628, + 'Viber' => 33049, + 'Videocon' => 33261, + 'Vimeo' => 37232, + 'Vodafone' => 33254, + 'Warframe' => 37124, + 'Wattpad' => 34698, + 'Waze' => 33408, + 'Webex' => 34163, + 'WeChat' => 33396, + 'Whatsapp' => 32867, + 'Wikipedia' => 33245, + 'Xbox Live' => 32866, + 'Yahoo' => 32859, + 'Yahoo Mail' => 33246, + 'Yahoo Messenger' => 33247, + 'You Broadband' => 34763, + 'Youtube' => 32858, + 'Zee5' => 38647, + 'Zerodha' => 37207, + 'ZoHo' => 37552, + 'Zomato' => 37672, + ), + 'Portugal' => array( + 'ActivoBank' => 33959, + 'Apex Legends' => 38127, + 'Apple Store' => 34464, + 'Banco Espírito Santo' => 33961, + 'Banco Santander Totta' => 33960, + 'Binance' => 36945, + 'Bing' => 33925, + 'Blizzard Battle.net' => 37225, + 'Cabovisão' => 33956, + 'Caixa Geral de Depósitos' => 33957, + 'Call of Duty' => 38982, + 'Clash Royale' => 38957, + 'Counter-Strike' => 36651, + 'Dead By Daylight' => 37429, + 'Deezer' => 33927, + 'Destiny' => 38964, + 'Discord' => 37388, + 'Dota 2' => 38479, + 'EA' => 36452, + 'eBay' => 33928, + 'Facebook' => 33929, + 'Facebook Messenger' => 34847, + 'Facetime' => 34586, + 'Fifa' => 36905, + 'Fortnite' => 36695, + 'Gmail' => 33930, + 'Go Daddy' => 34849, + 'Google' => 33931, + 'Google Play' => 33932, + 'GTA 5' => 36857, + 'HBO' => 38379, + 'iCloud' => 33933, + 'iMessage' => 33934, + 'Instagram' => 33963, + 'iTunes' => 33935, + 'Kik' => 33943, + 'Kraken' => 36980, + 'League of Legends' => 38635, + 'LinkedIn' => 33936, + 'MEO' => 33950, + 'Millennium Bcp' => 33958, + 'Montepio' => 33962, + 'Netflix' => 37301, + 'NOS' => 33952, + 'Office 365' => 37175, + 'OLX' => 33949, + 'OneDrive' => 36870, + 'Optimus' => 33951, + 'Origin' => 36892, + 'Outlook' => 33937, + 'Overwatch' => 37082, + 'Paypal' => 33938, + 'Pinterest' => 37373, + 'Player Unknown\'s Battlegrounds' => 36566, + 'Playstation Network' => 33939, + 'Pokémon Go' => 35754, + 'Rainbow Six' => 36454, + 'Reddit' => 38068, + 'Roblox' => 38920, + 'Rocket League' => 36668, + 'Skype' => 33940, + 'Snapchat' => 36742, + 'Spotify' => 33964, + 'Steam' => 34138, + 'Teamviewer' => 35691, + 'Telegram' => 37186, + 'Tinder' => 37921, + 'Twitch' => 36453, + 'Twitter' => 33941, + 'Uplay PC' => 38651, + 'Uzo' => 33954, + 'Viber' => 33942, + 'Vodafone' => 33953, + 'Warframe' => 37135, + 'Whatsapp' => 34855, + 'Wikipedia' => 33944, + 'Xbox Live' => 33945, + 'Yahoo' => 33946, + 'Yahoo Mail' => 33947, + 'Youtube' => 33948, + 'Z1 Battle Royale' => 37264, + ), + 'Schweiz' => array( + 'Airbnb' => 37666, + 'Anthem' => 38205, + 'Apex Legends' => 38130, + 'App Store' => 35583, + 'Apple Store' => 34462, + 'Battlefield' => 38050, + 'Bet365' => 38831, + 'Binance' => 36935, + 'Blizzard Battle.net' => 36569, + 'Call of Duty' => 34157, + 'Clash Royale' => 38958, + 'Coinbase' => 36805, + 'Counter-strike' => 36646, + 'Crunchyroll' => 38144, + 'Dazn' => 36509, + 'Dead By Daylight' => 37413, + 'Deezer' => 34038, + 'Destiny' => 36591, + 'Discord' => 37389, + 'Dota 2' => 35402, + 'Dropbox' => 34039, + 'EA' => 34503, + 'eBay' => 34040, + 'Epic Games Store' => 39026, + 'Evard' => 35642, + 'Facebook' => 34041, + 'Facebook Messenger' => 34885, + 'Facetime' => 34585, + 'Fifa' => 37089, + 'flashcable' => 37202, + 'Flickr' => 34042, + 'For Honor' => 35997, + 'Fortnite' => 36688, + 'Ghost Recon' => 36006, + 'Gmail' => 34043, + 'GMX' => 34044, + 'Google' => 34045, + 'Google Hangouts' => 34046, + 'Google Play' => 34047, + 'Green' => 36971, + 'Grindr' => 38742, + 'GTA 5' => 35502, + 'Guild Wars 2' => 36465, + 'Hay Day' => 34853, + 'iCloud' => 34048, + 'ICQ' => 34049, + 'iMessage' => 34050, + 'Instagram' => 34051, + 'iTunes' => 34052, + 'Kik' => 34054, + 'Kraken' => 36807, + 'League of Legends' => 35574, + 'LinkedIn' => 34055, + 'Lovoo' => 35401, + 'Mail.de' => 38629, + 'Netatmo' => 38467, + 'Netflix' => 34632, + 'Nitrado' => 35547, + 'Office 365' => 36581, + 'OneDrive' => 35413, + 'Origin' => 36891, + 'Outlook' => 34057, + 'Overwatch' => 36152, + 'Peoplefone' => 36602, + 'Playerunknown\'s Battlegrounds' => 36560, + 'Playstation Network' => 34087, + 'Pokémon Go' => 35744, + 'PostFinance' => 36048, + 'Protonmail' => 35643, + 'Quickline' => 36970, + 'Quizduell' => 34529, + 'Rainbow Six' => 36147, + 'Red Dead Redemption' => 37741, + 'Reddit' => 38067, + 'Ricardo' => 34079, + 'Rocket League' => 35486, + 'Salt' => 35602, + 'Search.ch' => 34080, + 'Sky Sport' => 37069, + 'Skype' => 34059, + 'Snapchat' => 34060, + 'Spotify' => 34061, + 'SRF' => 34081, + 'Steam' => 34226, + 'Sunrise' => 34078, + 'Swisscom' => 34077, + 'Tango' => 34062, + 'Teamviewer' => 34616, + 'Telegram' => 35968, + 'The elder scrolls online' => 35763, + 'Threema' => 34256, + 'Tinder' => 34244, + 'Tumblr' => 34063, + 'TuneIn' => 38775, + 'Tutti' => 36014, + 'Tweakbox' => 38904, + 'Twint' => 38183, + 'Twitch' => 35505, + 'Twitter' => 34064, + 'UBS' => 34082, + 'UPC' => 34075, + 'Uplay PC' => 34690, + 'Viber' => 34065, + 'Viewster' => 34325, + 'Vimeo' => 34066, + 'Waze' => 34067, + 'Web.de' => 34068, + 'Whatsapp' => 34069, + 'Wikipedia' => 34070, + 'World of Warships' => 38015, + 'Xbox Live' => 34088, + 'Yahoo Mail' => 34072, + 'Yahoo Messenger' => 34073, + 'Yallo' => 37298, + 'Youtube' => 34074, + 'Z1 Battle Royale' => 35492, + 'Zattoo' => 35366, + ), + 'Singapore' => array( + 'Airbnb' => 37608, + 'Apex Legends' => 38182, + 'App Store' => 37735, + 'Apple Store' => 34682, + 'Binance' => 36944, + 'Bing' => 34652, + 'Blizzard Battle.net' => 36431, + 'Brawl Stars' => 38820, + 'Call of Duty' => 39051, + 'Clash of Clans' => 34667, + 'Clash Royale' => 38952, + 'Counter-strike' => 36556, + 'DBS' => 34658, + 'Destiny' => 38986, + 'Discord' => 37100, + 'Dota 2' => 35875, + 'Dropbox' => 34671, + 'EA' => 36429, + 'Facebook' => 34645, + 'Facebook Messenger' => 34646, + 'Facetime' => 34681, + 'Fifa' => 38398, + 'Fortnite' => 37321, + 'Ghost Recon' => 38995, + 'Gmail' => 34647, + 'Google' => 34648, + 'Google Drive' => 34649, + 'Google Hangouts' => 38364, + 'Google Play' => 38519, + 'Grindr' => 36754, + 'GTA 5' => 37278, + 'HSBC' => 34672, + 'iCloud' => 34685, + 'iMessage' => 34684, + 'Instagram' => 34665, + 'iTunes' => 34683, + 'League of Legends' => 38748, + 'Line' => 34740, + 'LinkedIn' => 34656, + 'M1' => 34662, + 'Microsoft Azure' => 36113, + 'Minecraft' => 38738, + 'My Republic' => 36463, + 'Netflix' => 36391, + 'Office 365' => 37173, + 'OkCupid' => 38490, + 'Origin' => 38377, + 'Outlook' => 34673, + 'Overwatch' => 36389, + 'Path of Exile' => 37723, + 'Player Unknown\'s Battlegrounds' => 36361, + 'Playstation Network' => 34668, + 'Pokémon Go' => 35757, + 'POSB' => 34738, + 'Rainbow Six' => 36382, + 'Reddit' => 37475, + 'Roblox' => 37286, + 'SingTel' => 34661, + 'Skype' => 36418, + 'Snapchat' => 34666, + 'Spotify' => 34739, + 'Standard Chartered' => 34743, + 'Starhub' => 34663, + 'Steam' => 36430, + 'Summoners War' => 37421, + 'Taobao' => 34660, + 'Telegram' => 36381, + 'Tinder' => 37137, + 'Tumblr' => 36711, + 'Tweakbox' => 38345, + 'Twitch' => 36539, + 'Twitter' => 34659, + 'Uplay PC' => 37521, + 'Viber' => 34670, + 'Viewqwest' => 37506, + 'Warframe' => 36494, + 'WeChat' => 34674, + 'Whatsapp' => 34664, + 'Whisper' => 34624, + 'Wikipedia' => 34655, + 'Xbox Live' => 34669, + 'Yahoo' => 34654, + 'Yahoo Mail' => 34653, + 'Youtube' => 34650, + ), + 'Türkiye' => array( + 'Akbank' => 33783, + 'Anthem' => 38195, + 'Apex Legends' => 38121, + 'Apple Store' => 34451, + 'Battlefield' => 38449, + 'Binance' => 36952, + 'Blizzard Battle.net' => 37224, + 'Call of Duty' => 38940, + 'Counter-strike' => 36652, + 'D-Smart' => 34422, + 'Dead By Daylight' => 37433, + 'Denizbank' => 33788, + 'Destiny' => 38984, + 'Discord' => 36766, + 'Dota 2' => 36396, + 'EA' => 36157, + 'Facebook' => 33748, + 'Facebook Messenger' => 33749, + 'Facetime' => 34588, + 'Fifa' => 37087, + 'Finansbank' => 33786, + 'For Honor' => 37369, + 'Fortnite' => 36698, + 'Garanti' => 33780, + 'GittiGidiyor' => 33779, + 'Gmail' => 33750, + 'Google' => 33751, + 'Google Hangouts' => 33752, + 'Google Play' => 33753, + 'Gran Turismo' => 36947, + 'GTA 5' => 37276, + 'HalkBank' => 33784, + 'HSBC' => 33790, + 'iCloud' => 33754, + 'iMessage' => 33755, + 'ING Bank' => 33789, + 'Instagram' => 33732, + 'iTunes' => 33756, + 'Kik' => 33757, + 'Kraken' => 36986, + 'LinkedIn' => 33758, + 'Messageme' => 33727, + 'Netflix' => 37300, + 'Office 365' => 38058, + 'Origin' => 36901, + 'Outlook' => 33759, + 'Overwatch' => 36386, + 'Player Unknown\'s Battlegrounds' => 36456, + 'Playstation Network' => 33760, + 'Rainbow Six' => 36154, + 'Reddit' => 38064, + 'Roblox' => 38915, + 'Rocket League' => 36669, + 'Sahibinden' => 33778, + 'Skype' => 33761, + 'Snapchat' => 33762, + 'Steam' => 37322, + 'Tango' => 33730, + 'Telegram' => 37090, + 'Tinder' => 37911, + 'Ttnet' => 33776, + 'Türk Ekonomi Bankası (TEB)' => 33791, + 'Türk Telekom' => 33771, + 'Turkcell' => 33774, + 'Türkiye İş Bankası' => 33781, + 'Türksat Kablo' => 33772, + 'Twitch' => 35506, + 'Twitter' => 33613, + 'Uplay PC' => 36156, + 'VakıfBank' => 33785, + 'Viber' => 33733, + 'Vodafone' => 33775, + 'Warframe' => 37128, + 'Whatsapp' => 33764, + 'Xbox Live' => 33766, + 'Yahoo Mail' => 38885, + 'Yandex' => 33777, + 'Yapı Kredi' => 33782, + 'Youtube' => 33767, + 'Ziraat Bankası' => 33787, + ), + 'Suomi' => array( + 'Aktia' => 36308, + 'Apex Legends' => 38123, + 'Battlefield' => 37096, + 'Binance' => 36929, + 'Blizzard Battle.net' => 36299, + 'Call of Duty' => 36706, + 'Clash Royale' => 38947, + 'Counter-strike' => 36645, + 'Crunchyroll' => 38097, + 'Dankse Bank' => 36307, + 'Dead By Daylight' => 37428, + 'Destiny' => 38531, + 'Discord' => 36681, + 'DNA' => 36304, + 'Dota 2' => 36434, + 'EA' => 36295, + 'Elisa' => 36303, + 'Epic Games Store' => 39030, + 'Escape from Tarkov' => 39057, + 'Facebook' => 36237, + 'Facebook Messenger' => 36240, + 'Faceit' => 39038, + 'Fifa' => 37603, + 'Fortnite' => 36691, + 'Ghost Recon' => 38998, + 'Gmail' => 36254, + 'Google' => 36253, + 'Google Play' => 38522, + 'Gran Turismo' => 36912, + 'GTA 5' => 36844, + 'Guild Wars 2' => 36471, + 'HBO Nordic' => 36302, + 'iCloud' => 38841, + 'Instagram' => 36435, + 'Kraken' => 36852, + 'League of Legends' => 38632, + 'Minecraft' => 38616, + 'Netflix' => 36252, + 'Nordea' => 36306, + 'Office 365' => 36297, + 'OP' => 36305, + 'Origin' => 36904, + 'Outlook' => 36251, + 'Overwatch' => 36250, + 'Path of Exile' => 36530, + 'Paypal' => 37347, + 'Playerunknown\'s Battlegrounds' => 36339, + 'Playstation Network' => 36249, + 'Pokémon Go' => 36248, + 'Rainbow Six' => 36247, + 'Reddit' => 36823, + 'Roblox' => 38913, + 'Rocket League' => 36300, + 'Runescape' => 38655, + 'Sea of Thieves' => 37118, + 'Skype' => 36246, + 'Slack' => 37496, + 'Snapchat' => 36245, + 'Spotify' => 37078, + 'Steam' => 36296, + 'Telegram' => 37091, + 'Telia' => 36287, + 'Tinder' => 36298, + 'Twitch' => 36436, + 'Twitter' => 36677, + 'Uplay PC' => 36244, + 'Viaplay' => 37294, + 'Viber' => 37494, + 'Warframe' => 36704, + 'Whatsapp' => 36243, + 'Wikipedia' => 38871, + 'World of Tanks' => 36673, + 'Xbox Live' => 36301, + 'Yahoo Mail' => 38883, + 'Youtube' => 36242, + 'Z1 Battle Royale' => 37259, + ), + 'France' => array( + 'Albion Online' => 38796, + 'Alexa' => 38030, + 'Alice' => 34009, + 'Amazon' => 32693, + 'Amazon Web Services' => 38109, + 'Ameli' => 38705, + 'Amen' => 35888, + 'Anthem' => 38207, + 'Apex Legends' => 38116, + 'App Store' => 35582, + 'Apple Store' => 34469, + 'AXA Banque' => 33427, + 'Bankin\'' => 37592, + 'Banque Populaire' => 33432, + 'Battlefield' => 38057, + 'Betclic' => 39046, + 'Binance' => 36939, + 'Bing' => 32696, + 'BlaBlaCar' => 36089, + 'Blizzard Battle.net' => 36437, + 'Blogger' => 32697, + 'BNP Paribas' => 32749, + 'Boom Beach' => 35154, + 'Bouygues Télécom' => 32747, + 'Brawl Stars' => 38815, + 'Caisse d\'allocations familiales' => 38708, + 'Caisse d\'Epargne' => 33428, + 'Call of Duty' => 35037, + 'CanalSat' => 34034, + 'Candy Crush' => 35881, + 'Cdiscount' => 35038, + 'CIC' => 33431, + 'Clash Royale' => 38151, + 'Cloudflare' => 38622, + 'Coinbase' => 36830, + 'Completel' => 33982, + 'Compte Nickel' => 35983, + 'Counter-Strike' => 36649, + 'Crédit Agricole' => 32753, + 'Crédit Mutuel' => 33429, + 'Crunchyroll' => 38096, + 'Dartybox' => 32848, + 'Dead By Daylight' => 37425, + 'Deezer' => 32843, + 'Destiny' => 34951, + 'Discord' => 36763, + 'Dofus Touch' => 38711, + 'Dota 2' => 35877, + 'Dropbox' => 32700, + 'Duel Quiz' => 34530, + 'EA' => 32844, + 'eBay' => 32701, + 'Elite: Dangerous' => 37776, + 'Epic Games Store' => 39029, + 'Escape from Tarkov' => 39058, + 'Facebook' => 32702, + 'Facebook Messenger' => 32703, + 'Facetime' => 34602, + 'Fallout' => 37667, + 'Fifa' => 35475, + 'Flickr' => 32704, + 'Fnac' => 35065, + 'For Honor' => 35995, + 'Fortnite' => 36656, + 'Free' => 32744, + 'Gandi' => 38712, + 'Ghost Recon' => 38959, + 'GitHub' => 32705, + 'Gmail' => 32706, + 'Google' => 32707, + 'Google Agenda' => 38601, + 'Google Drive' => 36608, + 'Google Hangouts' => 32709, + 'Google Play' => 32708, + 'Gran Turismo' => 36911, + 'Grindr' => 36756, + 'GTA 5' => 35039, + 'Guild Wars 2' => 36468, + 'Hearthstone' => 38562, + 'Hootsuite' => 32710, + 'Hue' => 37815, + 'Hunt: showdown' => 38824, + 'iCloud' => 32712, + 'Idealo' => 34890, + 'iMessage' => 32713, + 'ING Direct' => 33426, + 'Instagram' => 32715, + 'iTunes' => 32716, + 'JeuxVidéo' => 32847, + 'K-net' => 37790, + 'Kraken' => 36753, + 'La Banque Postale' => 32754, + 'La Poste' => 37215, + 'La Poste Mobile' => 32752, + 'LCL (Crédit Lyonnais)' => 33424, + 'Le Bon Coin' => 32840, + 'League of Legends' => 35369, + 'LinkedIn' => 32717, + 'LycaMobile' => 32849, + 'M6 Mobile' => 32845, + 'Magic' => 37456, + 'Météo France' => 38706, + 'Microsoft Azure' => 36115, + 'Minecraft' => 32718, + 'Molotov.TV' => 35965, + 'myCanal' => 38710, + 'Netatmo' => 37957, + 'Netflix' => 34633, + 'Nintendo eShop' => 34103, + 'Nordnet' => 38709, + 'NRJ Mobile' => 32846, + 'Numéricable' => 32748, + 'OCS' => 38707, + 'Office 365' => 35126, + 'Onedrive' => 35409, + 'Online.net' => 36159, + 'Orange' => 32745, + 'Orange Bank' => 37511, + 'Origin' => 36896, + 'Outlook' => 32711, + 'Overwatch' => 36151, + 'OVH' => 34744, + 'Paladins' => 36378, + 'Path of Exile' => 36855, + 'Paypal' => 32842, + 'Photobucket' => 32721, + 'Pinterest' => 32722, + 'Player Unknown\'s Battlegrounds' => 36363, + 'Playstation Network' => 32741, + 'Pokémon Go' => 35735, + 'Prime Video' => 38457, + 'Rainbow Six' => 35562, + 'Rakuten TV' => 37596, + 'Realm Royale' => 37308, + 'Red Dead Redemption' => 38287, + 'Reddit' => 37368, + 'Roblox' => 38755, + 'Rocket League' => 35253, + 'Salesforce' => 38501, + 'Sea of Thieves' => 37117, + 'SFR' => 32746, + 'Shadow' => 37212, + 'Skype' => 32723, + 'Skyrock.com' => 33430, + 'Slack' => 37337, + 'Slideshare' => 32724, + 'Snapchat' => 33378, + 'Société Générale' => 33425, + 'Sosh' => 34830, + 'Spotify' => 32727, + 'Star Citizen' => 39037, + 'Steam' => 32742, + 'Streamlabs' => 38927, + 'Syma' => 37449, + 'Tango' => 34482, + 'Teamviewer' => 34908, + 'Telegram' => 34230, + 'The elder scrolls online' => 37326, + 'Tinder' => 34808, + 'Tumblr' => 32728, + 'TuneIn' => 38758, + 'Tweakbox' => 38347, + 'Twitch' => 35027, + 'Twitter' => 32729, + 'Uber Eats' => 38897, + 'Unibet' => 38274, + 'Uplay PC' => 35544, + 'Viber' => 33373, + 'Vimeo' => 32730, + 'Warface' => 38776, + 'Warframe' => 36368, + 'Waze' => 33410, + 'WeTransfer' => 32731, + 'Whatsapp' => 32575, + 'Wibox' => 37055, + 'Wikipedia' => 32732, + 'Wordpress.com' => 32734, + 'World of Tanks' => 36030, + 'Xbox Live' => 32743, + 'Yahoo' => 32735, + 'Yahoo Mail' => 32736, + 'Yahoo Messenger' => 32737, + 'Youtube' => 32739, + 'Z1 Battle Royale' => 37260, + 'Zynga' => 32740, + ), + 'Brasil' => array( + 'Albion Online' => 38797, + 'Alelo' => 37410, + 'Algar' => 37507, + 'Alog' => 34746, + 'Amazon' => 33206, + 'Amazon Prime Video' => 38754, + 'Amazon Web Services' => 34091, + 'America Net' => 35127, + 'Anthem' => 38211, + 'Anydesk' => 37492, + 'Apex Legends' => 38126, + 'App Store' => 39054, + 'Apple Store' => 34449, + 'Avianca' => 36519, + 'Azul' => 36358, + 'Banco Central do Brasil' => 36002, + 'Banco do Brasil' => 34037, + 'Banco Inter' => 37559, + 'Banco Itaú' => 33205, + 'Banco Safra' => 37151, + 'Banco Santander' => 33381, + 'Banestes' => 37065, + 'Banrisul' => 35425, + 'Battlefield' => 38447, + 'Betfair' => 38188, + 'Binance' => 36940, + 'Bing' => 33215, + 'Blizzard Battle.net' => 36671, + 'Bradesco' => 33197, + 'Brisanet' => 36967, + 'Buscapé' => 35167, + 'C6 Bank' => 38773, + 'Cabo Telecom' => 33991, + 'Cabonnet' => 35919, + 'Caixa Econômica Federal' => 33191, + 'Call of Duty' => 38163, + 'Claro' => 33199, + 'Clash of Clans' => 37303, + 'Clash Royale' => 36053, + 'Clear' => 37557, + 'Cloudflare' => 38621, + 'Clusterweb' => 35967, + 'Copel Telecom' => 35671, + 'Correios' => 34611, + 'Counter-Strike' => 38162, + 'Credit Suisse' => 37978, + 'Crunchyroll' => 37138, + 'Dataprev' => 35137, + 'Dead By Daylight' => 36596, + 'Deezer' => 33385, + 'Destiny' => 38943, + 'Discord' => 37392, + 'Dota 2' => 35879, + 'Dropbox' => 33214, + 'EA' => 34500, + 'eBay' => 33207, + 'eCAC' => 34961, + 'Embratel' => 33999, + 'Enem' => 35136, + 'Epic Games Store' => 39031, + 'eSocial' => 35427, + 'Faceapp' => 38696, + 'Facebook' => 33184, + 'Facebook Messenger' => 34846, + 'Facetime' => 34597, + 'Feedly' => 34723, + 'Fifa' => 37769, + 'For Honor' => 37371, + 'Fortnite' => 36699, + 'Free Fire' => 38804, + 'Garena' => 38301, + 'Getnet' => 36745, + 'GitHub' => 38591, + 'Globo' => 34721, + 'Gmail' => 33194, + 'Go Daddy' => 34848, + 'Gol' => 38600, + 'Google' => 33186, + 'Google Cloud' => 38535, + 'Google Play' => 33211, + 'GTA 5' => 34757, + 'GVT' => 33562, + 'HBO' => 36354, + 'Hostgator' => 34745, + 'Hostnet' => 35850, + 'HSBC' => 34644, + 'iCloud' => 33219, + 'ICQ' => 34765, + 'iFood ' => 36960, + 'iMessage' => 33165, + 'Instagram' => 33204, + 'ITMNetworks' => 36094, + 'iTunes' => 33208, + 'Jurassic World Alive' => 37335, + 'Kik' => 34856, + 'KingHost' => 34957, + 'Kraken' => 36979, + 'League of Legends' => 39018, + 'Ligue Telecom' => 37526, + 'Line' => 33736, + 'LinkedIn' => 33210, + 'Locaweb' => 34722, + 'Mandic' => 36090, + 'Mercado Bitcoin' => 36790, + 'Mercado Livre' => 34234, + 'Microsoft Azure' => 36111, + 'Multiplay' => 37221, + 'NET' => 33190, + 'Netflix' => 33222, + 'Neverwinter' => 36158, + 'Nextel' => 33202, + 'Nota fiscal eletrônica' => 34718, + 'Nubank' => 37063, + 'Office 365' => 37170, + 'Oi' => 33196, + 'OLX' => 34235, + 'OneDrive' => 36866, + 'Origin' => 36903, + 'Outlook' => 33221, + 'Overwatch' => 36502, + 'PagSeguro' => 37313, + 'Path of Exile' => 37725, + 'Paypal' => 33213, + 'Pinterest' => 38164, + 'Player Unknown\'s Battlegrounds' => 36565, + 'Playstation Network' => 33217, + 'Pokémon Go' => 35751, + 'Polícia Federal' => 35135, + 'Porto Seguro Conecta' => 35981, + 'QConcursos' => 36601, + 'Rainbow Six' => 36451, + 'Receita Federal' => 34960, + 'Red Dead Redemption' => 38909, + 'Reddit' => 37477, + 'Roblox' => 37399, + 'Rocket League' => 38558, + 'Salesforce' => 38494, + 'Sefaz' => 37626, + 'Sercomtel' => 33990, + 'Sicoob' => 37624, + 'Sicredi' => 37505, + 'SiSU' => 38029, + 'SKY' => 33875, + 'Skype' => 33203, + 'Slack' => 37339, + 'Snapchat' => 33379, + 'Spotify' => 36594, + 'Steam' => 34137, + 'Submarino' => 35074, + 'SuperDigital' => 36744, + 'Teamviewer' => 35690, + 'Telegram' => 34937, + 'Terra' => 33193, + 'TIM' => 34686, + 'Tinder' => 36550, + 'Tribunal Superior Eleitoral' => 37578, + 'Twitch' => 36372, + 'Twitter' => 33195, + 'Uber' => 37767, + 'Udemy' => 38313, + 'Umbler' => 37577, + 'UOL' => 33189, + 'UOLHost' => 34748, + 'Uplay PC' => 38636, + 'Viber' => 33386, + 'Vimeo' => 38533, + 'Vivo' => 33192, + 'Vono' => 35138, + 'Warframe' => 36702, + 'Waze' => 33383, + 'WeChat' => 33735, + 'Whatsapp' => 32837, + 'Wikipedia' => 33198, + 'World of Warcraft' => 38879, + 'Xbox Live' => 33216, + 'Yahoo' => 33187, + 'Yahoo Mail' => 33201, + 'Youtube' => 33185, + 'Zello' => 33387, + ), + 'Россия' => array( + 'Albion Online' => 38798, + 'Anthem' => 38191, + 'Apex Legends' => 38138, + 'Apple Music' => 39012, + 'Apple Store' => 34470, + 'avito' => 37696, + 'Battlefield' => 38448, + 'Binance' => 37021, + 'Blizzard Battle.net' => 36784, + 'Call of Duty' => 39052, + 'Citilink' => 37700, + 'Cloudflare' => 38619, + 'Counter-strike' => 38234, + 'Dead By Daylight' => 37430, + 'Destiny' => 38941, + 'DNS Shop' => 37701, + 'Dota 2' => 36395, + 'EA' => 36924, + 'eBay' => 32799, + 'Elite: Dangerous' => 37775, + 'Facetime' => 34599, + 'Fifa' => 38428, + 'For Honor' => 37370, + 'Fortnite' => 37143, + 'GitHub' => 38713, + 'Gmail' => 32798, + 'GTA 5' => 36845, + 'iCloud' => 38840, + 'ICQ' => 33122, + 'iMessage' => 33115, + 'Interzet' => 33563, + 'iTunes' => 33114, + 'Ivi' => 34807, + 'Kraken' => 36982, + 'Last FM' => 36533, + 'Mail.Ru' => 33113, + 'Megogo' => 38198, + 'NetByNet' => 35927, + 'Okko' => 38793, + 'Origin' => 36900, + 'Outlook' => 33116, + 'Overwatch' => 36385, + 'Ozon' => 37702, + 'Path of Exile' => 37724, + 'Paypal' => 33118, + 'Player Unknown\'s Battlegrounds' => 36455, + 'Playstation Network' => 32801, + 'Qip' => 37697, + 'Qiwi' => 33504, + 'Rainbow Six' => 36457, + 'Reddit' => 38066, + 'Roblox' => 38922, + 'SkyNet' => 35103, + 'Slack' => 37340, + 'Snapchat' => 37144, + 'Teamviewer' => 34347, + 'Telegram' => 36734, + 'The elder scrolls online' => 37323, + 'Tumblr' => 37284, + 'Twitter' => 32797, + 'Uplay PC' => 35611, + 'Viber ' => 33402, + 'Warframe' => 37126, + 'WebMoney' => 33119, + 'Wildberries' => 37699, + 'World of Tanks' => 35051, + 'Xbox Live' => 32802, + 'Yahoo' => 32792, + 'Yahoo Mail' => 32793, + 'Yahoo Messenger' => 32794, + 'Yota' => 34356, + 'Акадо' => 34429, + 'Альфа-Банк' => 33110, + 'Банк ДОМ.РФ' => 38704, + 'Билайн' => 32850, + 'Ватсап' => 32803, + 'Википедия' => 33120, + 'ВКонтакте' => 32851, + 'ВТБ 24' => 33109, + 'ГИС ЖКХ' => 35822, + 'Гугл' => 32788, + 'Гугл Hangouts' => 32789, + 'Гугл Плей' => 32790, + 'Дискорд ' => 37386, + 'Дом.ru' => 34395, + 'Инстаграм' => 36069, + 'Кинопаб' => 38199, + 'Летай' => 34430, + 'МГТС' => 33108, + 'МегаФон' => 33104, + 'Мотив' => 33864, + 'МТС' => 33121, + 'НСПК ' => 35608, + 'Одноклассники' => 33112, + 'Почта России' => 36587, + 'Рамблер' => 37441, + 'Релком' => 34357, + 'Росреестр' => 38311, + 'Ростелеком' => 33105, + 'Сбербанк' => 33106, + 'СДЭК' => 38729, + 'Скай Линк' => 34358, + 'Скайп' => 32804, + 'Стим' => 34266, + 'Твич' => 36543, + 'Теле2' => 33818, + 'Тиндер' => 37919, + 'Тинькофф Банк ' => 37698, + 'ТТК' => 34359, + 'Уфанет' => 34431, + 'Фейсбук' => 32795, + 'Фейсбук Мессенджер' => 32796, + 'ФНС' => 38648, + 'Хоум Кредит' => 38627, + 'ЭлЖур ' => 37515, + 'Ютуб' => 32791, + 'Яндекс' => 33111, + 'Яндекс.Музыка' => 39013, + 'Яндекс.Навигатор' => 39014, + ), + 'España' => array( + 'Alexa' => 38032, + 'Amazon' => 33140, + 'Amazon Prime Video' => 38753, + 'Anthem' => 38201, + 'Anydesk' => 37490, + 'Apex Legends' => 38122, + 'App Store' => 38553, + 'Apple Store' => 34465, + 'Banco Popular' => 33135, + 'Banco Sabadell' => 33151, + 'Banco Santander' => 33132, + 'Bankia' => 33134, + 'Bankinter' => 33143, + 'Battlefield' => 39017, + 'BBVA' => 33133, + 'Binance' => 36936, + 'Blizzard Battle.net' => 36105, + 'Brawl Stars' => 38832, + 'Cableworld' => 37457, + 'Call of Duty' => 35538, + 'Clash of Clans' => 34362, + 'Clash Royale' => 38951, + 'Coinbase' => 36803, + 'Counter Strike' => 38239, + 'Crunchyroll' => 38147, + 'Dazn' => 39005, + 'Dead By Daylight' => 36597, + 'Deezer' => 33830, + 'Destiny' => 38944, + 'Discord' => 37387, + 'Dota 2' => 37188, + 'Dropbox' => 33142, + 'EA' => 36449, + 'eBay' => 33267, + 'Epic Games Store' => 39032, + 'Euskaltel' => 34442, + 'Facebook' => 32829, + 'Facebook Messenger' => 32830, + 'Facetime' => 34600, + 'Fifa' => 37088, + 'For Honor' => 36182, + 'Fortnite' => 36694, + 'Ghost Recon' => 38996, + 'Github' => 36521, + 'Gmail' => 32832, + 'Google' => 32822, + 'Google Drive' => 36605, + 'Google Hangouts' => 32823, + 'Google Play' => 33226, + 'Gran Turismo' => 36950, + 'Grindr' => 38401, + 'GTA 5' => 37274, + 'Guild Wars 2' => 36485, + 'HBO' => 36497, + 'Ibercaja' => 33153, + 'iCloud' => 33227, + 'iMessage' => 32980, + 'ING Direct' => 33148, + 'Instagram' => 33147, + 'iTunes' => 33144, + 'Jazztel' => 33129, + 'Kraken' => 36806, + 'League of Legends' => 38634, + 'Line' => 33394, + 'LinkedIn' => 33150, + 'Llamaya' => 38315, + 'Lowi' => 35832, + 'MásMóvil' => 36068, + 'Mil Anuncios' => 33141, + 'Movistar' => 33124, + 'Nest' => 38551, + 'Netflix' => 35565, + 'Office 365' => 35442, + 'OneDrive' => 36864, + 'ONO' => 33128, + 'Orange' => 33126, + 'Origin' => 36895, + 'Outlook' => 33220, + 'Overwatch' => 36387, + 'Pasion.com' => 37141, + 'Path of Exile' => 37770, + 'Paypal' => 33145, + 'Pepephone' => 33130, + 'Player Unknown\'s Battlegrounds' => 36561, + 'Playstation Network' => 32835, + 'Pokémon Go' => 35750, + 'Quantis' => 37050, + 'R' => 34441, + 'Rainbow Six' => 36145, + 'Rakuten TV' => 37595, + 'Reddit' => 37476, + 'Roblox' => 38928, + 'Rocket League' => 36181, + 'Sea of Thieves' => 37119, + 'Segunda Mano' => 33138, + 'Simyo' => 33131, + 'Sky' => 37520, + 'Skype' => 32838, + 'Slack' => 37342, + 'Snapchat' => 33380, + 'Spotify' => 33146, + 'Steam' => 34280, + 'Tango' => 33746, + 'Teamviewer' => 35688, + 'Telecable' => 34443, + 'Telegram' => 35352, + 'Tinder' => 36548, + 'Tuenti' => 33137, + 'Tweakbox' => 38350, + 'Twitch' => 36545, + 'Twitter' => 32831, + 'Unicaja' => 33149, + 'Uplay PC' => 35615, + 'Vibbo' => 36183, + 'Viber' => 33374, + 'Vodafone' => 33125, + 'Warframe' => 36705, + 'Whatsapp' => 33263, + 'Wikipedia' => 33139, + 'Xbox Live' => 32836, + 'Yahoo' => 32826, + 'Yahoo Mail' => 32827, + 'Yahoo Messenger' => 32828, + 'Yoigo' => 33127, + 'Youtube' => 32825, + 'Z1 Battle Royale' => 37263, + ), + 'Polska' => array( + 'Allegro' => 33799, + 'Amazon' => 33633, + 'Apex Legends' => 38124, + 'Apple Store' => 34453, + 'Bank Millennium' => 37535, + 'Bank Pekao' => 37534, + 'Battlefield' => 37471, + 'BGŻ BNP Paribas' => 37530, + 'Binance' => 36946, + 'Blizzard Battle.net' => 36783, + 'Call of Duty' => 38923, + 'Chomikuj' => 33803, + 'Clash Royale' => 38950, + 'Cloudflare' => 38624, + 'Counter-Strike' => 36648, + 'Cyfrowy Polsat' => 33866, + 'Dead By Daylight' => 36599, + 'Deezer' => 33837, + 'Destiny' => 38945, + 'Deutsche bank Polska' => 36176, + 'Discord' => 36761, + 'Dota 2' => 36447, + 'Dropbox' => 33796, + 'EA' => 36448, + 'East&West' => 35641, + 'eBay' => 38579, + 'Elite: Dangerous' => 37778, + 'Epic Games Store' => 39022, + 'Escape from Tarkov' => 39060, + 'Eurobank' => 37008, + 'Facebook' => 33634, + 'Facebook Messenger' => 33635, + 'Facetime' => 34591, + 'Fifa' => 37086, + 'For Honor' => 37305, + 'Fortnite' => 36693, + 'Get in Bank' => 37532, + 'GG (Gadu Gadu)' => 33809, + 'Ghost Recon' => 38997, + 'GitHub' => 38466, + 'Gmail' => 33636, + 'Google' => 33637, + 'Google Hangouts' => 33638, + 'Google Play' => 33639, + 'Gran Turismo' => 36916, + 'Grindr' => 38741, + 'GTA 5' => 36848, + 'Guild Wars 2' => 36467, + 'Gumtree' => 33805, + 'HBO' => 36355, + 'Heyah' => 33812, + 'Home.pl' => 37537, + 'iCloud' => 33640, + 'Idea Bank' => 37533, + 'iMessage' => 33641, + 'Inea' => 34415, + 'ING Bank' => 33807, + 'Instagram' => 33642, + 'iTunes' => 33643, + 'Kraken' => 36983, + 'League of Legends' => 36629, + 'LinkedIn' => 33806, + 'Mbank' => 33800, + 'Multimedia Polska' => 33879, + 'Nazwa' => 37320, + 'Nest Bank' => 37529, + 'Netflix' => 35728, + 'Netia' => 33815, + 'NK.pl (Nasza-klasa)' => 33808, + 'O2' => 33801, + 'Office 365' => 35125, + 'OLX' => 33802, + 'OneDrive' => 36868, + 'Orange' => 33810, + 'Origin' => 36899, + 'Outlook' => 33644, + 'Overwatch' => 36388, + 'Path of Exile' => 37728, + 'PKO Bank Polski' => 36044, + 'Play' => 33813, + 'Player Unknown\'s Battlegrounds' => 36580, + 'Playstation Network' => 33645, + 'Plus' => 33814, + 'Pokémon Go' => 35752, + 'Rainbow Six' => 36394, + 'Reddit' => 37485, + 'Roblox' => 37400, + 'Rocket League' => 36667, + 'Santander' => 37531, + 'Sea of Thieves' => 37120, + 'Skype' => 33793, + 'Slack' => 37338, + 'Snapchat' => 33797, + 'Spotify' => 33836, + 'Steam' => 34279, + 'T-Mobile' => 33811, + 'Teamviewer' => 35694, + 'Telegram' => 35970, + 'The elder scrolls online' => 37328, + 'Tinder' => 36547, + 'Tumblr' => 37285, + 'Twitch' => 36450, + 'Twitter' => 33646, + 'UPC' => 33816, + 'Uplay PC' => 35612, + 'Vectra' => 33817, + 'Viber' => 33794, + 'Warframe' => 36493, + 'Whatsapp' => 33792, + 'Wikipedia' => 33647, + 'World of Tanks' => 36029, + 'World of Warcraft' => 37446, + 'World of Warships' => 38008, + 'Xbox Live' => 33648, + 'Yahoo Mail' => 38887, + 'Youtube' => 33649, + 'Z1 Battle Royale' => 37267, + ), + 'Norge' => array( + 'Altibox' => 36318, + 'Anthem' => 38206, + 'Apex Legends' => 38120, + 'App Store' => 38100, + 'Battlefield' => 37098, + 'Binance' => 36928, + 'Blizzard Battle.net' => 36309, + 'Call of Duty' => 36708, + 'Coinbase' => 36799, + 'Counter-strike' => 36647, + 'Crunchyroll' => 36720, + 'Danske Bank' => 36321, + 'Dead By Daylight' => 37426, + 'Destiny' => 36592, + 'Discord' => 36762, + 'Dota 2' => 36442, + 'EA' => 36310, + 'Epic Games Store' => 39028, + 'Facebook' => 36238, + 'Facebook Messenger' => 36269, + 'Fifa' => 36908, + 'Fortnite' => 36687, + 'Get' => 36319, + 'Ghost Recon' => 39000, + 'Gmail' => 36255, + 'Google' => 36256, + 'Google Drive' => 36760, + 'Google Play' => 38528, + 'GTA 5' => 36847, + 'Guild Wars 2' => 36470, + 'HBO Nordic' => 36316, + 'iCloud' => 38844, + 'Ikano Bank' => 36577, + 'Instagram' => 36443, + 'Kraken' => 36853, + 'League of Legends' => 38630, + 'Minecraft' => 37280, + 'Netflix' => 36257, + 'NexGenTel' => 36320, + 'Nordea' => 36325, + 'Norges Bank' => 36324, + 'Office 365' => 36311, + 'OneDrive' => 36865, + 'Origin' => 36893, + 'Outlook' => 36258, + 'Overwatch' => 36259, + 'Path of Exile' => 37727, + 'Playerunknown\'s Battlegrounds' => 36338, + 'Playstation Network' => 36260, + 'Pokémon Go' => 36261, + 'Rainbow Six' => 36262, + 'Realm Royale' => 37316, + 'Red Dead Redemption' => 38283, + 'Reddit' => 36825, + 'Roblox' => 38919, + 'Rocket League' => 36312, + 'Sea of Thieves' => 37116, + 'Skype' => 36263, + 'Snapchat' => 36264, + 'Sparebanken 1' => 36323, + 'Spotify' => 36796, + 'Steam' => 36313, + 'Strava' => 38730, + 'Tele2' => 36317, + 'Telegram' => 37183, + 'Telenor' => 36288, + 'The elder scrolls online' => 37324, + 'Tinder' => 36314, + 'Twitch' => 36444, + 'Twitter' => 37268, + 'Uplay PC' => 36265, + 'Viaplay' => 37293, + 'Warframe' => 37129, + 'Whatsapp' => 36266, + 'Wikipedia' => 38872, + 'World of Warcraft' => 37447, + 'Xbox Live' => 36315, + 'Yahoo' => 36268, + 'Yahoo Mail' => 38890, + 'Youtube' => 36267, + 'Z1 Battle Royale' => 37262, + ), + 'México' => array( + 'Amazon' => 33292, + 'Amazon Prime Video' => 38752, + 'Anthem' => 38192, + 'Apex Legends' => 38139, + 'App Store' => 37732, + 'Apple Store' => 34466, + 'AT&T' => 35861, + 'Axtel' => 34439, + 'Banamex' => 33322, + 'Banco Santander' => 36772, + 'Banorte' => 33326, + 'Battlefield' => 38445, + 'BBVA Bancomer' => 33321, + 'Binance' => 37019, + 'Blizzard Battle.net' => 36106, + 'Cablecom' => 34035, + 'Cablemás' => 34438, + 'Call of Duty' => 35540, + 'Clash of Clans' => 37099, + 'Crunchyroll' => 37139, + 'Dead By Daylight' => 37432, + 'Deezer' => 33397, + 'Destiny' => 38966, + 'Discord' => 38606, + 'Dropbox' => 33294, + 'EA' => 36609, + 'eBay' => 33295, + 'Facebook' => 33296, + 'Facebook Messenger' => 33297, + 'Facetime' => 34594, + 'Fifa' => 38307, + 'Fortnite' => 36842, + 'Gears of War' => 38893, + 'Gmail' => 33298, + 'Go Daddy' => 36620, + 'Google' => 33299, + 'Google Drive' => 38260, + 'Google Hangouts' => 33300, + 'Google Play' => 33301, + 'Gran Turismo' => 36951, + 'Grindr' => 38740, + 'GTA 5' => 38275, + 'HBO' => 36351, + 'iCloud' => 33302, + 'iMessage' => 33303, + 'Instagram' => 33304, + 'iTunes' => 33305, + 'Izzi' => 37685, + 'League of Legends' => 39019, + 'Line' => 33395, + 'LinkedIn' => 33306, + 'Megacable' => 34437, + 'Mercado Libre' => 33320, + 'Microsoft Azure' => 37466, + 'Minecraft' => 38737, + 'Movistar' => 33307, + 'Netflix' => 33325, + 'Origin' => 38103, + 'Outlook' => 33308, + 'Overwatch' => 36483, + 'Paypal' => 33309, + 'Player Unknown\'s Battlegrounds' => 36562, + 'Playstation Network' => 33310, + 'Pokémon Go' => 36360, + 'Rainbow Six' => 36146, + 'Reddit' => 37482, + 'Roblox' => 38917, + 'Salesforce' => 38496, + 'Scotiabank' => 37686, + 'Segunda Mano' => 33327, + 'SKY México' => 33328, + 'Skype' => 33311, + 'Snapchat' => 34288, + 'SPEI' => 37689, + 'Spotify' => 33398, + 'Steam' => 34281, + 'Tango' => 33745, + 'Teamviewer' => 35689, + 'Telcel' => 33319, + 'Telegram' => 35852, + 'Telmex' => 33324, + 'Telnor' => 34440, + 'Tinder' => 37165, + 'Totalplay' => 37687, + 'Tweakbox' => 38903, + 'Twitch' => 36546, + 'Twitter' => 33312, + 'Unefon' => 37688, + 'WeChat' => 33399, + 'Whatsapp' => 33313, + 'Wikipedia' => 33314, + 'World of Warcraft' => 38880, + 'Xbox Live' => 33315, + 'Yahoo' => 33316, + 'Yahoo Mail' => 33317, + 'Yahoo Messenger' => 33318, + 'Youtube' => 33361, + 'Zello' => 33388, + ), + '日本' => array( + 'Amazon' => 33464, + 'Amazon Web Services' => 34094, + 'Amazon インスタント・ビデオ' => 34496, + 'Apex Legends' => 38177, + 'App Store' => 35581, + 'Apple Store' => 34467, + 'ASAHI ネット' => 33859, + 'Au' => 33465, + 'Biglobe' => 33479, + 'Blizzard Battle.net' => 36672, + 'bmobile' => 33466, + 'Call of Duty' => 39053, + 'Dazn' => 36511, + 'Discord' => 38613, + 'Disney Mobile' => 33467, + 'DMM' => 35818, + 'Dropbox' => 33441, + 'EA' => 37080, + 'eBay' => 33442, + 'EO Net' => 33863, + 'Facebook' => 33443, + 'Facebook Messenger' => 33444, + 'Facetime' => 34593, + 'FC2' => 34510, + 'Fortnite' => 37162, + 'Freetel' => 35620, + 'Ghost Recon' => 38993, + 'Github' => 37375, + 'Gmail' => 33445, + 'Google' => 33446, + 'Google Hangouts' => 33447, + 'Google Play' => 33448, + 'Hulu' => 33480, + 'iCloud' => 33449, + 'IIJ' => 34511, + 'iMessage' => 33450, + 'Instagram' => 33451, + 'iTunes' => 33452, + 'Jcom' => 33478, + 'League of Legends' => 38899, + 'Line' => 33453, + 'LinkedIn' => 33454, + 'Livedoor' => 33472, + 'Microsoft Azure' => 36110, + 'Netflix' => 36728, + 'Nifty' => 33473, + 'Nintendo Network' => 35521, + 'NTT Docomo' => 33474, + 'NTT東日本' => 33475, + 'NTT西日本' => 33476, + 'OCN' => 33564, + 'Office 365' => 35928, + 'OneDrive' => 36496, + 'Outlook' => 33455, + 'Paypal' => 33456, + 'Player Unknown\'s Battlegrounds' => 36616, + 'Playstation Network' => 33457, + 'Rakuten' => 34513, + 'Reddit' => 37478, + 'Skype' => 33458, + 'Slack' => 37358, + 'Snapchat' => 38511, + 'So-net' => 33862, + 'Steam' => 38649, + 'Telegram' => 37227, + 'Tinder' => 37916, + 'Twitter' => 33459, + 'UQ Wimax' => 33482, + 'Whatsapp' => 38255, + 'Xbox Live' => 33471, + 'Yahoo' => 33460, + 'Yahoo BB' => 33860, + 'Yahoo Mail' => 33461, + 'Yammer' => 35560, + 'Youtube' => 33462, + 'じぶん銀行' => 33500, + 'ぷらら' => 33861, + 'みずほ銀行' => 33493, + 'りそな銀行' => 33496, + 'アメーバブログ' => 34514, + 'カカオトーク' => 33469, + 'ジャパンネット銀行' => 33497, + 'スカパー' => 33477, + 'スポナビLive' => 36516, + 'ソニー銀行' => 33498, + 'ソフトバンク' => 33470, + 'ポケモン go' => 35746, + 'ワイモバイル' => 36503, + '三井住友銀行' => 33495, + '三菱東京UFJ銀行' => 33494, + '埼玉りそな銀行' => 36532, + '楽天銀行' => 33499, + '近畿大阪銀行' => 36531, + ), + 'Pilipinas' => array( + 'Anthem' => 38193, + 'Apex Legends' => 38158, + 'Battlefield' => 37925, + 'Blizzard Battle.net' => 37834, + 'Converge' => 38714, + 'Counter-strike' => 38241, + 'Destiny' => 38987, + 'Discord' => 38453, + 'Dota 2' => 37835, + 'EA' => 37931, + 'Facebook' => 37836, + 'Facebook Messenger' => 37837, + 'Fortnite' => 37930, + 'Globe' => 37941, + 'Gmail' => 38080, + 'Google' => 37838, + 'Google Drive' => 38259, + 'Google Hangouts' => 38365, + 'Google Play' => 38521, + 'GTA 5' => 38718, + 'iCloud' => 38853, + 'Instagram' => 37839, + 'League of Legends' => 38911, + 'Mobile legends' => 38175, + 'Netflix' => 37840, + 'Office 365' => 37936, + 'Origin' => 38397, + 'Outlook' => 37935, + 'Overwatch' => 37932, + 'Paypal' => 38463, + 'Player Unknown\'s Battlegrounds' => 37841, + 'Playstation Network' => 38736, + 'PLDT' => 37938, + 'Rainbow Six' => 37933, + 'Reddit' => 38089, + 'Roblox' => 37927, + 'Sky Cable' => 37942, + 'Skype' => 37929, + 'Smart' => 37940, + 'Spotify' => 38644, + 'Steam' => 37924, + 'Telegram' => 38019, + 'Tinder' => 37912, + 'TNT' => 37943, + 'Twitter' => 37928, + 'Warframe' => 37934, + 'Wattpad' => 38962, + 'Waze' => 38267, + 'Whatsapp' => 38254, + 'Yahoo' => 37926, + 'Yahoo Mail' => 38456, + 'Youtube' => 37842, + ), + 'Indonesia' => array( + 'Anthem' => 38194, + 'Apex Legends' => 38181, + 'Biznet' => 38975, + 'Blizzard Battle.net' => 37825, + 'Clash of Clans' => 37961, + 'Counter-strike' => 38410, + 'Discord' => 38084, + 'Dota 2' => 37826, + 'EA' => 38419, + 'Facebook' => 37827, + 'Fifa' => 38427, + 'First Media' => 38974, + 'Fortnite' => 38532, + 'Gmail' => 38250, + 'Google' => 37828, + 'Google Drive' => 38262, + 'Google Play' => 38518, + 'GTA 5' => 38700, + 'iCloud' => 38851, + 'Indosat Ooredoo' => 38978, + 'Instagram' => 37829, + 'Myrepublic' => 38972, + 'Netflix' => 37830, + 'Origin' => 38376, + 'Pinterest' => 37950, + 'Player Unknown\'s Battlegrounds' => 37831, + 'Playstation Network' => 38735, + 'Reddit' => 38498, + 'Roblox' => 38914, + 'Steam' => 38098, + 'Telegram' => 38020, + 'Telkom' => 38973, + 'Telkomsel' => 38976, + 'Tinder' => 37915, + 'Twitter' => 38160, + 'Uplay PC' => 37962, + 'Whatsapp' => 37832, + 'XL' => 38977, + 'Yahoo Mail' => 38889, + 'Youtube' => 37833, + ), + 'Pakistan' => array( + 'Apex Legends' => 38414, + 'App Store' => 38960, + 'Battlefield' => 38002, + 'Blizzard Battle.net' => 37992, + 'Call of Duty' => 38939, + 'Discord' => 37993, + 'Dota 2' => 38476, + 'EA' => 38418, + 'Facebook' => 37994, + 'Facebook Messenger' => 37995, + 'Fiberlink' => 38006, + 'Fifa' => 38425, + 'Fortnite' => 38252, + 'Google' => 37996, + 'iCloud' => 38715, + 'Instagram' => 37997, + 'Kik' => 38539, + 'Netflix' => 37998, + 'Pinterest' => 38679, + 'Player Unknown\'s Battlegrounds' => 37999, + 'Playstation Network' => 38571, + 'PTLC' => 38004, + 'Quora' => 38908, + 'Snapchat' => 38508, + 'Steam' => 38341, + 'Tinder' => 38000, + 'Tumblr' => 38546, + 'Twitter' => 38678, + 'Wateen' => 38007, + 'Wattpad' => 38544, + 'Whatsapp' => 38003, + 'Yahoo Mail' => 38882, + 'Youtube' => 38001, + 'Zong' => 38005, + ), + 'UAE' => array( + 'Apex Legends' => 38159, + 'beIN' => 39073, + 'Binance' => 37022, + 'Blizzard Battle.net' => 36214, + 'Botim' => 38393, + 'Call of Duty' => 38935, + 'Cloudflare' => 38642, + 'Counter-strike' => 38269, + 'Dead By Daylight' => 37437, + 'Discord' => 37773, + 'Dota 2' => 36423, + 'Du' => 36235, + 'EA' => 36883, + 'Etisalat' => 36234, + 'Facebook' => 36215, + 'Facebook Messenger' => 36233, + 'Fifa' => 38433, + 'For Honor' => 36216, + 'Fortnite' => 36996, + 'Gmail' => 36217, + 'Google' => 36218, + 'iCloud' => 38843, + 'Instagram' => 36420, + 'Netflix' => 36219, + 'Office 365' => 38041, + 'Origin' => 38422, + 'Outlook' => 36220, + 'Overwatch' => 36221, + 'Player Unknown\'s Battlegrounds' => 36618, + 'Playstation Network' => 36222, + 'Pokémon Go' => 36223, + 'Rainbow Six' => 36224, + 'Reddit' => 38499, + 'Roblox' => 37222, + 'Rocket League' => 36231, + 'Skype' => 36225, + 'Snapchat' => 36226, + 'Steam' => 38340, + 'Telegram' => 37185, + 'Tinder' => 36227, + 'Twitter' => 38677, + 'Uplay PC' => 36228, + 'Whatsapp' => 36229, + 'Wikipedia' => 38878, + 'Xbox Live' => 38404, + 'Yahoo' => 36232, + 'Yahoo Mail' => 38888, + 'Youtube' => 36230, + 'ZoHo' => 37553, + ), + 'Malaysia' => array( + 'Apex Legends' => 38179, + 'Blizzard Battle.net' => 37891, + 'Counter-strike' => 38409, + 'Destiny' => 38985, + 'Discord' => 37976, + 'Dota 2' => 38017, + 'EA' => 38420, + 'Facebook' => 37892, + 'Facebook Messenger' => 37893, + 'Fifa' => 38429, + 'Gmail' => 38251, + 'Google' => 37894, + 'Google Drive' => 38263, + 'Google Play' => 38529, + 'GTA 5' => 38488, + 'iCloud' => 38850, + 'Instagram' => 37895, + 'League of Legends' => 38910, + 'Line' => 38386, + 'LinkedIn' => 38150, + 'Maxis' => 37964, + 'Netflix' => 37896, + 'Origin' => 38395, + 'Overwatch' => 38895, + 'Paypal' => 38461, + 'Player Unknown\'s Battlegrounds' => 37897, + 'Playstation Network' => 38570, + 'Reddit' => 38363, + 'Roblox' => 38912, + 'Snapchat' => 38548, + 'Steam' => 38081, + 'TIME' => 37965, + 'Tinder' => 37917, + 'Twitter' => 38481, + 'Unifi' => 37963, + 'Uplay PC' => 38896, + 'Waze' => 38268, + 'Whatsapp' => 38028, + 'Yahoo Mail' => 38891, + 'Youtube' => 37898, + ), + 'Perú' => array( + 'Apex Legends' => 39015, + 'Bitel' => 37982, + 'Claro' => 37981, + 'Crunchyroll' => 38550, + 'Dota 2' => 38353, + 'EA' => 38415, + 'Econocable' => 37983, + 'Entel' => 37980, + 'Facebook' => 37791, + 'Facebook Messenger' => 38258, + 'Fortnite' => 37792, + 'Gmail' => 37944, + 'Google' => 37945, + 'HBO' => 38369, + 'iCloud' => 38855, + 'Instagram' => 37793, + 'Movistar' => 37794, + 'Netflix' => 38594, + 'Origin' => 38423, + 'Outlook' => 38581, + 'Playstation Network' => 38568, + 'Spotify' => 38580, + 'Steam' => 38099, + 'Telegram' => 38483, + 'Tinder' => 37909, + 'Twitter' => 38105, + 'Whatsapp' => 37795, + 'Youtube' => 37796, + ), + 'Argentina' => array( + 'Apex Legends' => 38129, + 'Arnet' => 37969, + 'Banco Galicia' => 36132, + 'Banco Nación' => 36131, + 'Banco Provincia' => 36133, + 'Banco Santander Río ' => 36130, + 'BBVA Francés' => 36134, + 'Binance' => 37020, + 'Blizzard Battle.net' => 36104, + 'Call of Duty' => 36743, + 'Claro' => 36100, + 'Clash of Clans' => 36128, + 'Correo Argentino' => 36999, + 'Counter-Strike' => 38247, + 'Crunchyroll' => 38091, + 'Dead By Daylight' => 37431, + 'Destiny' => 38965, + 'Discord' => 38614, + 'Dota 2' => 37187, + 'EA' => 36885, + 'Facebook' => 36072, + 'Facebook Messenger' => 36073, + 'Fibertel' => 36635, + 'Fifa' => 38435, + 'Flow' => 38309, + 'Fortnite' => 37017, + 'Free Fire' => 38806, + 'Gigared' => 38215, + 'Gmail' => 37716, + 'Google' => 36074, + 'Google Play' => 38520, + 'GTA 5' => 38276, + 'HBO' => 36352, + 'ICBC' => 38646, + 'iCloud' => 38858, + 'Instagram' => 36075, + 'Mercado Libre' => 36076, + 'Microsoft Azure' => 37467, + 'Movistar' => 36077, + 'Netflix' => 36078, + 'Nextel' => 36103, + 'OLX' => 37045, + 'Origin' => 36902, + 'Outlook' => 36079, + 'Overwatch' => 38774, + 'Path of Exile' => 37771, + 'Personal' => 37970, + 'Player Unknown\'s Battlegrounds' => 36563, + 'Playstation Network' => 36080, + 'Pokémon Go' => 36294, + 'Rainbow Six' => 36144, + 'Reddit' => 37483, + 'Roblox' => 38929, + 'Skype' => 36081, + 'Snapchat' => 36082, + 'Spotify' => 36107, + 'Steam' => 36129, + 'Teamviewer' => 36142, + 'Telecentro' => 36810, + 'Telecom' => 36097, + 'Telefónica' => 36099, + 'Telegram' => 38485, + 'Telered' => 37971, + 'Tinder' => 37169, + 'Tuenti' => 38628, + 'Twitch' => 36544, + 'Twitter' => 36109, + 'Uplay PC' => 36143, + 'Waze' => 37470, + 'Whatsapp' => 36083, + 'Wikipedia' => 37352, + 'World of Warcraft' => 38778, + 'Xbox Live' => 37443, + 'Yahoo Mail' => 36084, + 'Youtube' => 36085, + ), + 'Slovensko' => array( + 'Apex Legends' => 38131, + 'Blizzard Battle.net' => 37875, + 'Counter-strike' => 38243, + 'Discord' => 38612, + 'Dota 2' => 38480, + 'EA' => 38417, + 'Facebook' => 37876, + 'Facebook Messenger' => 37877, + 'Fifa' => 38426, + 'Fortnite' => 38807, + 'Google' => 37878, + 'GTA 5' => 38279, + 'HBO Go' => 38381, + 'iCloud' => 38848, + 'Instagram' => 37879, + 'Netflix' => 37880, + 'Origin' => 38374, + 'Player Unknown\'s Battlegrounds' => 37881, + 'Playstation Network' => 38572, + 'Reddit' => 38809, + 'Snapchat' => 38513, + 'Steam' => 38230, + 'Twitter' => 38669, + 'Whatsapp' => 38371, + 'Wikipedia' => 38877, + 'Xbox Live' => 38088, + 'Yahoo Mail' => 38881, + 'Youtube' => 37882, + ), + 'Ελλάς' => array( + 'Apex Legends' => 38132, + 'Bet365' => 38811, + 'Blizzard Battle.net' => 37843, + 'Clash Royale' => 38949, + 'Counter-strike' => 38235, + 'Destiny' => 38980, + 'Discord' => 38607, + 'Dota 2' => 38352, + 'EA' => 38416, + 'eBay' => 38578, + 'Facebook' => 37844, + 'Facebook Messenger' => 37845, + 'Fifa' => 38434, + 'Fortnite' => 38087, + 'Gmail' => 38079, + 'Google' => 37846, + 'Google Play' => 38527, + 'GTA 5' => 38701, + 'iCloud' => 38846, + 'Instagram' => 37847, + 'League of Legends' => 38618, + 'Netflix' => 37848, + 'Office 365' => 38076, + 'Origin' => 38375, + 'Paypal' => 38462, + 'Player Unknown\'s Battlegrounds' => 37849, + 'Playstation Network' => 38575, + 'Pokémon Go' => 38639, + 'Reddit' => 38516, + 'Snapchat' => 38505, + 'Steam' => 38231, + 'Twitch' => 38582, + 'Twitter' => 38676, + 'Viber' => 38588, + 'Whatsapp' => 38373, + 'Yahoo Mail' => 38892, + 'Youtube' => 37850, + 'Βικιπαίδεια' => 38873, + ), + 'Hrvatska' => array( + 'Apex Legends' => 38135, + 'Battlefield' => 38442, + 'Blizzard Battle.net' => 37859, + 'Clash Royale' => 38356, + 'Counter-strike' => 38244, + 'Destiny' => 39011, + 'Discord' => 38610, + 'Dota 2' => 38351, + 'EA' => 38036, + 'Facebook' => 37860, + 'Facebook Messenger' => 37861, + 'Fifa' => 38438, + 'Fortnite' => 38069, + 'Google' => 37862, + 'GTA 5' => 38278, + 'HBO Go' => 38384, + 'iCloud' => 38847, + 'Instagram' => 37863, + 'Netflix' => 37864, + 'Office 365' => 38075, + 'Origin' => 38149, + 'Player Unknown\'s Battlegrounds' => 37865, + 'Playstation Network' => 38574, + 'Reddit' => 38090, + 'Snapchat' => 38509, + 'Steam' => 38229, + 'Tinder' => 37920, + 'Twitter' => 38672, + 'Whatsapp' => 38026, + 'Wikipedia' => 38874, + 'Yahoo Mail' => 38884, + 'Youtube' => 37866, + ), + 'Česko' => array( + 'Apex Legends' => 38136, + 'Battlefield' => 38446, + 'Blizzard Battle.net' => 37851, + 'Counter-strike' => 38236, + 'Discord' => 38452, + 'Dota 2' => 38221, + 'EA' => 38037, + 'Facebook' => 37852, + 'Facebook Messenger' => 37853, + 'Fifa' => 38430, + 'Fortnite' => 38086, + 'Gmail' => 38515, + 'Google' => 37854, + 'Google Play' => 38523, + 'GTA 5' => 38304, + 'HBO Go' => 38380, + 'iCloud' => 38845, + 'Instagram' => 37855, + 'Netflix' => 37856, + 'Office 365' => 38042, + 'Origin' => 38043, + 'Player Unknown\'s Battlegrounds' => 37857, + 'Playstation Network' => 38573, + 'Reddit' => 38062, + 'Snapchat' => 38512, + 'Steam' => 38082, + 'Tinder' => 37914, + 'Twitch' => 38530, + 'Twitter' => 38675, + 'Uplay PC' => 38638, + 'Whatsapp' => 38025, + 'Xbox Live' => 38072, + 'Youtube' => 37858, + ), + 'Chile' => array( + 'Apex Legends' => 38137, + 'Banco Estado' => 37682, + 'Banco Santander' => 37351, + 'Blizzard Battle.net' => 38104, + 'Call of Duty' => 38938, + 'Claro' => 36290, + 'Clash of Clans' => 37304, + 'Correos' => 37025, + 'Counter-Strike' => 38246, + 'Crunchyroll' => 38093, + 'Dead By Daylight' => 37436, + 'Discord' => 37758, + 'Dota 2' => 38477, + 'EA' => 36884, + 'Entel' => 37680, + 'Facebook' => 36239, + 'Facebook Messenger' => 36285, + 'Falabella' => 37681, + 'Fifa' => 38432, + 'Fortnite' => 36997, + 'Gmail' => 36499, + 'Google' => 36284, + 'Google Drive' => 38560, + 'GTA 5' => 38305, + 'Gtd Manquehue' => 37683, + 'HBO' => 36353, + 'iCloud' => 38854, + 'Instagram' => 36283, + 'Itaú' => 38473, + 'LinkedIn' => 38625, + 'Movistar' => 36289, + 'Mundo Pacifico' => 37684, + 'Netflix' => 36282, + 'Office 365' => 38077, + 'Origin' => 38102, + 'Outlook' => 36281, + 'Player Unknown\'s Battlegrounds' => 36564, + 'Playstation Network' => 36280, + 'Pokémon Go' => 36293, + 'Rainbow Six' => 36270, + 'Reddit' => 37484, + 'Roblox' => 38930, + 'SII' => 37679, + 'Skype' => 36279, + 'Snapchat' => 36278, + 'Spotify' => 36274, + 'Steam' => 36272, + 'Teamviewer' => 37068, + 'Telegram' => 38170, + 'Telsur' => 36292, + 'Tinder' => 37907, + 'Twitch' => 36541, + 'Twitter' => 36273, + 'Uplay PC' => 36271, + 'VTR' => 36291, + 'Warframe' => 37123, + 'Whatsapp' => 36277, + 'Wom' => 38308, + 'Xbox Live' => 37024, + 'Yahoo Mail' => 36276, + 'Youtube' => 36275, + ), + 'Colombia' => array( + 'Apex Legends' => 38140, + 'BBVA' => 37781, + 'Blizzard Battle.net' => 38148, + 'Call of Duty' => 38937, + 'Claro' => 37788, + 'Directv' => 37968, + 'Discord' => 38552, + 'EA' => 38282, + 'ETB' => 37967, + 'Facebook' => 37782, + 'Facebook Messenger' => 38257, + 'Fifa' => 38431, + 'Fortnite' => 37783, + 'Free Fire' => 38805, + 'Gmail' => 37779, + 'Google' => 37780, + 'Google Drive' => 39067, + 'GTA 5' => 38277, + 'HBO' => 38370, + 'iCloud' => 38857, + 'Instagram' => 37784, + 'Movistar' => 37789, + 'Netflix' => 37820, + 'Origin' => 38424, + 'Outlook' => 38464, + 'Player Unknown\'s Battlegrounds' => 37785, + 'Playstation Network' => 38391, + 'Snapchat' => 38506, + 'Spotify' => 38168, + 'Steam' => 38933, + 'Teamviewer' => 38460, + 'Telegram' => 38484, + 'Tigo' => 37966, + 'Tinder' => 37908, + 'Twitter' => 38169, + 'Waze' => 39070, + 'Whatsapp' => 37786, + 'Xbox Live' => 38071, + 'Yahoo Mail' => 38924, + 'Youtube' => 37787, + ), + 'România' => array( + 'Apex Legends' => 38142, + 'Battlefield' => 38441, + 'Blizzard Battle.net' => 37867, + 'Brawl Stars' => 38817, + 'Call of Duty' => 38934, + 'Counter-strike' => 38237, + 'Destiny' => 38988, + 'Digi' => 38971, + 'Discord' => 37953, + 'Dota 2' => 38222, + 'EA' => 38039, + 'Facebook' => 37868, + 'Facebook Messenger' => 37869, + 'Fifa' => 38046, + 'Fortnite' => 38070, + 'Gmail' => 38549, + 'Google' => 37870, + 'Google Play' => 38524, + 'GTA 5' => 38281, + 'HBO Go' => 38383, + 'iCloud' => 38849, + 'Instagram' => 37871, + 'Netflix' => 37872, + 'Orange' => 38970, + 'Origin' => 38045, + 'Player Unknown\'s Battlegrounds' => 37873, + 'Playstation Network' => 38407, + 'Reddit' => 38063, + 'Roblox' => 38918, + 'Snapchat' => 38510, + 'Steam' => 38083, + 'Telekom' => 38931, + 'Tinder' => 37913, + 'Twitter' => 38674, + 'UPC' => 38968, + 'Uplay PC' => 38637, + 'Vodafone' => 38967, + 'Whatsapp' => 38027, + 'Wikipedia' => 38875, + 'Xbox Live' => 38073, + 'Yahoo Mail' => 38455, + 'Youtube' => 37874, + ), + 'Magyarország' => array( + 'Apex Legends' => 38143, + 'Battlefield' => 38450, + 'Blizzard Battle.net' => 37883, + 'Call of Duty' => 39004, + 'Counter-strike' => 38242, + 'Destiny' => 38979, + 'Discord' => 38454, + 'Dota 2' => 38475, + 'EA' => 38038, + 'Escape from Tarkov' => 39055, + 'Facebook' => 37884, + 'Facebook Messenger' => 37885, + 'Fifa' => 38437, + 'Fortnite' => 38808, + 'Ghost Recon' => 38991, + 'Gmail' => 38514, + 'Google' => 37886, + 'GTA 5' => 38280, + 'HBO Go' => 38382, + 'iCloud' => 38852, + 'Instagram' => 37887, + 'Mastercard' => 38592, + 'Netflix' => 37888, + 'Office 365' => 38040, + 'Origin' => 38044, + 'Outlook' => 38078, + 'Pinterest' => 37954, + 'Player Unknown\'s Battlegrounds' => 37889, + 'Playstation Network' => 38408, + 'Rainbow Six' => 38486, + 'Reddit' => 38065, + 'Snapchat' => 38507, + 'Steam' => 38232, + 'Tinder' => 37910, + 'Twitch' => 39016, + 'Twitter' => 38673, + 'Uplay PC' => 38354, + 'Whatsapp' => 38372, + 'Wikipedia' => 38876, + 'Xbox Live' => 38074, + 'Yahoo Mail' => 38886, + 'Youtube' => 37890, + ), + 'Ecuador' => array( + 'Call of Duty' => 38936, + 'Claro' => 37985, + 'CNT' => 37990, + 'EA' => 38421, + 'Facebook' => 37797, + 'Facebook Messenger' => 38256, + 'Fortnite' => 37798, + 'HBO' => 38368, + 'iCloud' => 38856, + 'Instagram' => 37799, + 'iPlanet' => 37986, + 'Movistar' => 37984, + 'Nedetel' => 37987, + 'Netflix' => 37819, + 'Netlife' => 37991, + 'Playstation Network' => 38577, + 'Puntonet' => 37988, + 'Steam' => 38932, + 'Telegram' => 38482, + 'TVCable' => 37989, + 'Twitter' => 38670, + 'Whatsapp' => 37800, + 'Youtube' => 37801, + ), + ) + ) + ), + ); + + const API_TOKEN = 'YW5kcm9pZF9hcGlfdXNlcl92MTpxTkRyenZSczY1bW1ESlk0ZVNIWmtobFY='; + + public function collectData(){ + + if($this->queriedContext == 'All Websites') { + $html = getSimpleHTMLDOM($this->getURI() . '/archive/') + or returnClientError('Impossible to query website !.'); + + $table = $html->find('table.table-striped', 0); + + $maxCount = 10; + foreach ($table->find('tr') as $downEvent) { + $downLink = $downEvent->find('td', 1)->find('a', 1); + $item = $this->collectArticleData($downLink->getAttribute('href')); + $this->items[] = $item; + if($maxCount == 0) break; + $maxCount -= 1; + } + } else { + $this->items = $this->collectCompanyEvents($this->getInput('website')); + } + } + + protected function collectArticleData($link) { + + preg_match('/\/([0-9]{3,})/', $link, $matches); + $eventId = $matches[1]; + + $header = array( + 'Authorization: Basic ' . self::API_TOKEN + ); + + $article = getContents('https://downdetectorapi.com/v1/events/' . $eventId, $header) + or returnServerError('Could not request DownDetector API.'); + $article_json = json_decode($article); + + $item = array(); + $item['uri'] = $this->getURI() . $link; + $item['id'] = $article_json->id; + $item['title'] = $article_json->title; + $item['content'] = $article_json->body; + $item['timestamp'] = (new DateTime($article_json->started_at))->getTimestamp(); + return $item; + + } + + protected function collectCompanyEvents($companyId) { + + $header = array( + 'Authorization: Basic ' . self::API_TOKEN + ); + + $events = getContents('https://downdetectorapi.com/v1/companies/' . $companyId . '/events/', $header) + or returnServerError('Could not request DownDetector API.'); + $events_json = json_decode($events); + + $items = array(); + + foreach($events_json as $event) { + $item = array(); + $item['id'] = $event->id; + $item['title'] = $event->title; + $item['content'] = $event->body; + $item['timestamp'] = (new DateTime($event->started_at))->getTimestamp(); + $items[] = $item; + } + + return $items; + + } + + public function getURI() { + if($this->getInput('country') !== null) { + return $this->getInput('country'); + } else { + return self::URI; + } + } +} diff --git a/bridges/DribbbleBridge.php b/bridges/DribbbleBridge.php index 5058da6..b1193c9 100644 --- a/bridges/DribbbleBridge.php +++ b/bridges/DribbbleBridge.php @@ -19,7 +19,7 @@ favicon-63b2904a073c89b52b19aa08cebc16a154bcf83fee8ecc6439968b1e6db569c7.ico'; $json = $this->loadEmbeddedJsonData($html); foreach($html->find('li[id^="screenshot-"]') as $shot) { - $item = []; + $item = array(); $additional_data = $this->findJsonForShot($shot, $json); if ($additional_data === null) { @@ -38,14 +38,14 @@ favicon-63b2904a073c89b52b19aa08cebc16a154bcf83fee8ecc6439968b1e6db569c7.ico'; $preview_path = $shot->find('picture source', 0)->attr['srcset']; $item['content'] .= $this->getImageTag($preview_path, $item['title']); - $item['enclosures'] = [$this->getFullSizeImagePath($preview_path)]; + $item['enclosures'] = array($this->getFullSizeImagePath($preview_path)); $this->items[] = $item; } } private function loadEmbeddedJsonData($html){ - $json = []; + $json = array(); $scripts = $html->find('script'); foreach($scripts as $script) { diff --git a/bridges/EconomistBridge.php b/bridges/EconomistBridge.php index 1256be4..94121ac 100644 --- a/bridges/EconomistBridge.php +++ b/bridges/EconomistBridge.php @@ -40,7 +40,7 @@ class EconomistBridge extends BridgeAbstract { if ($nextprev) $nextprev->outertext = ''; - $section = [ $article->find('h3[itemprop="articleSection"]', 0)->plaintext ]; + $section = array( $article->find('h3[itemprop="articleSection"]', 0)->plaintext ); $item = array(); $item['title'] = $header->find('span', 0)->innertext . ': ' diff --git a/bridges/ElloBridge.php b/bridges/ElloBridge.php index 3de167e..8bcfa92 100644 --- a/bridges/ElloBridge.php +++ b/bridges/ElloBridge.php @@ -95,7 +95,7 @@ class ElloBridge extends BridgeAbstract { private function getEnclosures($post, $postData) { - $assets = []; + $assets = array(); foreach($post->links->assets as $asset) { foreach($postData->linked->assets as $assetLink) { if($asset == $assetLink->id) { @@ -124,7 +124,7 @@ class ElloBridge extends BridgeAbstract { $cacheFac->setWorkingDir(PATH_LIB_CACHES); $cache = $cacheFac->create(Configuration::getConfig('cache', 'type')); $cache->setScope(get_called_class()); - $cache->setKey(['key']); + $cache->setKey(array('key')); $key = $cache->loadData(); if($key == null) { diff --git a/bridges/ElsevierBridge.php b/bridges/ElsevierBridge.php index 080fe00..01230a9 100644 --- a/bridges/ElsevierBridge.php +++ b/bridges/ElsevierBridge.php @@ -3,7 +3,7 @@ class ElsevierBridge extends BridgeAbstract { const MAINTAINER = 'Pierre Mazière'; const NAME = 'Elsevier journals recent articles'; - const URI = 'http://www.journals.elsevier.com/'; + const URI = 'https://www.journals.elsevier.com/'; const CACHE_TIMEOUT = 43200; //12h const DESCRIPTION = 'Returns the recent articles published in Elsevier journals'; diff --git a/bridges/EsquerdaNetBridge.php b/bridges/EsquerdaNetBridge.php new file mode 100644 index 0000000..f459eb2 --- /dev/null +++ b/bridges/EsquerdaNetBridge.php @@ -0,0 +1,70 @@ +<?php +class EsquerdaNetBridge extends FeedExpander { + const MAINTAINER = 'somini'; + const NAME = 'Esquerda.net'; + const URI = 'https://www.esquerda.net'; + const DESCRIPTION = 'Esquerda.net'; + const PARAMETERS = array( + array( + 'feed' => array( + 'name' => 'Feed', + 'type' => 'list', + 'defaultValue' => 'Geral', + 'values' => array( + 'Geral' => 'geral', + 'Dossier' => 'artigos-dossier', + 'Vídeo' => 'video', + 'Opinião' => 'opinioes', + 'Rádio' => 'radio', + ) + ) + ) + ); + + public function getURI() { + $type = $this->getInput('feed'); + return self::URI . '/rss/' . $type; + } + + public function getIcon() { + return 'https://www.esquerda.net/sites/default/files/favicon_0.ico'; + } + + public function collectData(){ + parent::collectExpandableDatas($this->getURI()); + } + + protected function parseItem($newsItem){ + # Fix Publish date + $badDate = $newsItem->pubDate; + preg_match('|(?P<day>\d\d)/(?P<month>\d\d)/(?P<year>\d\d\d\d) - (?P<hour>\d\d):(?P<minute>\d\d)|', $badDate, $d); + $newsItem->pubDate = sprintf('%s-%s-%sT%s:%s', $d['year'], $d['month'], $d['day'], $d['hour'], $d['minute']); + $item = parent::parseItem($newsItem); + # Include all the content + $uri = $item['uri']; + $html = getSimpleHTMLDOMCached($uri) + or returnServerError('Could not load content for ' . $uri); + $content = $html->find('div#content div.content', 0); + ## Fix author + $authorHTML = $html->find('.field-name-field-op-author a', 0); + if ($authorHTML) { + $item['author'] = $authorHTML->innertext; + $authorHTML->remove(); + } + ## Remove crap + $content->find('.field-name-addtoany', 0)->remove(); + ## Fix links + $content = defaultLinkTo($content, self::URI); + ## Fix Images + foreach($content->find('img') as $img) { + $altSrc = $img->getAttribute('data-src'); + if ($altSrc) { + $img->setAttribute('src', $altSrc); + } + $img->width = null; + $img->height = null; + } + $item['content'] = $content; + return $item; + } +} diff --git a/bridges/ExtremeDownloadBridge.php b/bridges/ExtremeDownloadBridge.php index acdf630..1b4aa9a 100644 --- a/bridges/ExtremeDownloadBridge.php +++ b/bridges/ExtremeDownloadBridge.php @@ -1,7 +1,7 @@ <?php class ExtremeDownloadBridge extends BridgeAbstract { const NAME = 'Extreme Download'; - const URI = 'https://ww1.extreme-d0wn.com/'; + const URI = 'https://wvw.extreme-down.xyz/'; const DESCRIPTION = 'Suivi de série sur Extreme Download'; const MAINTAINER = 'sysadminstory'; const PARAMETERS = array( diff --git a/bridges/FB2Bridge.php b/bridges/FB2Bridge.php index 2faa321..77ae271 100644 --- a/bridges/FB2Bridge.php +++ b/bridges/FB2Bridge.php @@ -2,7 +2,7 @@ class FB2Bridge extends BridgeAbstract { const MAINTAINER = 'teromene'; - const NAME = 'Facebook Alternate'; + const NAME = 'Facebook Bridge | Touch Site'; const URI = 'https://www.facebook.com/'; const CACHE_TIMEOUT = 1000; const DESCRIPTION = 'Input a page title or a profile log. For a profile log, @@ -12,7 +12,12 @@ class FB2Bridge extends BridgeAbstract { 'u' => array( 'name' => 'Username', 'required' => true - ) + ), + 'abbrev_name' => array( + 'name' => 'Abbreviate author name in title', + 'type' => 'checkbox', + 'defaultValue' => true, + ), )); public function getIcon() { @@ -102,12 +107,12 @@ EOD else $timestamp = 0; - $item['uri'] = html_entity_decode('http://touch.facebook.com' + $item['uri'] = html_entity_decode('https://touch.facebook.com' . $content->find("div[class='_52jc _5qc4 _78cz _24u0 _36xo']", 0)->find('a', 0)->getAttribute('href'), ENT_QUOTES); //Decode images $imagecleaned = preg_replace_callback('/<i [^>]* style="[^"]*url\(\'(.*?)\'\).*?><\/i>/m', function ($matches) { - return "<img src='" . str_replace(['\\3a ', '\\3d ', '\\26 '], [':', '=', '&'], $matches[1]) . "' />"; + return "<img src='" . str_replace(array('\\3a ', '\\3d ', '\\26 '), array(':', '=', '&'), $matches[1]) . "' />"; }, $content); $content = str_get_html($imagecleaned); @@ -159,7 +164,11 @@ EOD $content = preg_replace('/<img src=\'.*?safe_image\.php.*?\' \/>/m', '', $content); //Remove the double section tags - $content = str_replace(['<section><section>', '</section></section>'], ['<section>', '</section>'], $content); + $content = str_replace( + array('<section><section>', '</section></section>'), + array('<section>', '</section>'), + $content + ); //Move the section tag link upper, if it is down $content = str_get_html($content); @@ -182,8 +191,10 @@ EOD $item['content'] = html_entity_decode($content, ENT_QUOTES); $title = $author; - if (strlen($title) > 24) - $title = substr($title, 0, strpos(wordwrap($title, 24), "\n")) . '...'; + if ($this->getInput('abbrev_name') === true) { + if (strlen($title) > 24) + $title = substr($title, 0, strpos(wordwrap($title, 24), "\n")) . '...'; + } $title = $title . ' | ' . strip_tags($content); if (strlen($title) > 64) $title = substr($title, 0, strpos(wordwrap($title, 64), "\n")) . '...'; @@ -281,10 +292,20 @@ EOD } public function getName(){ - return (isset($this->name) ? $this->name . ' - ' : '') . 'Facebook Bridge'; + $username = $this->getInput('u'); + if (isset($username)) { + return $this->getInput('u') . ' | Facebook'; + } else { + return self::NAME; + } } public function getURI(){ - return 'http://facebook.com'; + $username = $this->getInput('u'); + if (isset($username)) { + return 'https://facebook.com/' . $this->getInput('u') . '/posts'; + } else { + return self::URI; + } } } diff --git a/bridges/FacebookBridge.php b/bridges/FacebookBridge.php index 08b3a38..5ce67f9 100644 --- a/bridges/FacebookBridge.php +++ b/bridges/FacebookBridge.php @@ -2,7 +2,7 @@ class FacebookBridge extends BridgeAbstract { const MAINTAINER = 'teromene, logmanoriginal'; - const NAME = 'Facebook Bridge'; + const NAME = 'Facebook Bridge | Main Site'; const URI = 'https://www.facebook.com/'; const CACHE_TIMEOUT = 300; // 5min const DESCRIPTION = 'Input a page title or a profile log. For a profile log, @@ -66,14 +66,13 @@ class FacebookBridge extends BridgeAbstract { case 'User': if(!empty($this->authorName)) { - return isset($this->extraInfos['name']) ? $this->extraInfos['name'] : $this->authorName - . ' - ' . static::NAME; + return isset($this->extraInfos['name']) ? $this->extraInfos['name'] : $this->authorName; } break; case 'Group': if(!empty($this->groupName)) { - return $this->groupName . ' - ' . static::NAME; + return $this->groupName; } break; @@ -82,6 +81,34 @@ class FacebookBridge extends BridgeAbstract { return parent::getName(); } + public function detectParameters($url){ + $params = array(); + + // By profile + $regex = '/^(https?:\/\/)?(www\.)?facebook\.com\/profile\.php\?id\=([^\/?&\n]+)?(.*)/'; + if(preg_match($regex, $url, $matches) > 0) { + $params['u'] = urldecode($matches[3]); + return $params; + } + + // By group + $regex = '/^(https?:\/\/)?(www\.)?facebook\.com\/groups\/([^\/?\n]+)?(.*)/'; + if(preg_match($regex, $url, $matches) > 0) { + $params['g'] = urldecode($matches[3]); + return $params; + } + + // By username + $regex = '/^(https?:\/\/)?(www\.)?facebook\.com\/([^\/?\n]+)/'; + + if(preg_match($regex, $url, $matches) > 0) { + $params['u'] = urldecode($matches[3]); + return $params; + } + + return null; + } + public function getURI() { $uri = self::URI; @@ -674,8 +701,15 @@ EOD; $uri = $post->find('abbr')[0]->parent()->getAttribute('href'); - if (false !== strpos($uri, '?')) { - $uri = substr($uri, 0, strpos($uri, '?')); + // Extract fbid and patch link + if (strpos($uri, '?') !== false) { + $query = substr($uri, strpos($uri, '?') + 1); + parse_str($query, $query_params); + if (isset($query_params['story_fbid'])) { + $uri = self::URI . $query_params['story_fbid']; + } else { + $uri = substr($uri, 0, strpos($uri, '?')); + } } //Build and add final item diff --git a/bridges/FreeCodeCampBridge.php b/bridges/FreeCodeCampBridge.php new file mode 100644 index 0000000..da0b5c7 --- /dev/null +++ b/bridges/FreeCodeCampBridge.php @@ -0,0 +1,27 @@ +<?php +class FreeCodeCampBridge extends FeedExpander { + + const MAINTAINER = 'IceWreck'; + const NAME = 'FreeCodecamp Bridge'; + const URI = 'https://www.freecodecamp.org'; + const CACHE_TIMEOUT = 3600; + const DESCRIPTION = 'RSS feed for FreeCodeCamp'; + // Freecodecamp removed their old full content rss feed and replaced it with one liner content. + + public function collectData(){ + $this->collectExpandableDatas('https://www.freecodecamp.org/news/rss/', 15); + } + + protected function parseItem($newsItem){ + $item = parent::parseItem($newsItem); + // $articlePage gets the entire page's contents + $articlePage = getSimpleHTMLDOM($newsItem->link); + // figure contain's the main article image + $article = $articlePage->find('figure', 0); + // the actual article + foreach($articlePage->find('.post-full-content') as $element) + $article = $article . $element; + $item['content'] = $article; + return $item; + } +} diff --git a/bridges/FurAffinityUserBridge.php b/bridges/FurAffinityUserBridge.php new file mode 100644 index 0000000..fd8a61f --- /dev/null +++ b/bridges/FurAffinityUserBridge.php @@ -0,0 +1,110 @@ +<?php +class FurAffinityUserBridge extends BridgeAbstract { + const NAME = 'FurAffinity User Gallery'; + const URI = 'https://www.furaffinity.net'; + const MAINTAINER = 'CyberJacob'; + const PARAMETERS = array( + array( + 'searchUsername' => array( + 'name' => 'Search Username', + 'type' => 'text', + 'required' => true, + 'title' => 'Username to fetch the gallery for' + ), + 'loginUsername' => array( + 'name' => 'Login Username', + 'type' => 'text', + 'required' => true + ), + 'loginPassword' => array( + 'name' => 'Login Password', + 'type' => 'text', + 'required' => true + ) + ) + ); + + public function collectData() { + $cookies = self::login(); + $url = self::URI . '/gallery/' . $this->getInput('searchUsername'); + + $html = getSimpleHTMLDOM($url, $cookies) + or returnServerError('Could not load the user\'s galary page.'); + + $submissions = $html->find('section[id=gallery-gallery]', 0)->find('figure'); + foreach($submissions as $submission) { + $item = array(); + $item['title'] = $submission->find('figcaption', 0)->find('a', 0)->plaintext; + + $thumbnail = $submission->find('a', 0); + $thumbnail->href = self::URI . $thumbnail->href; + + $item['content'] = $submission->find('a', 0); + + $this->items[] = $item; + } + } + + public function getName() { + return self::NAME . ' for ' . $this->getInput('searchUsername'); + } + + public function getURI() { + return self::URI . '/user/' . $this->getInput('searchUsername'); + } + + private function login() { + $ch = curl_init(self::URI . '/login/'); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); + + curl_setopt($ch, CURLOPT_USERAGENT, ini_get('user_agent')); + curl_setopt($ch, CURLOPT_ENCODING, ''); + curl_setopt($ch, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS); + + $fields = implode('&', array( + 'action=login', + 'retard_protection=1', + 'name=' . urlencode($this->getInput('loginUsername')), + 'pass=' . urlencode($this->getInput('loginPassword')), + 'login=Login to Faraffinity' + )); + + curl_setopt($ch, CURLOPT_POST, 5); + curl_setopt($ch, CURLOPT_POSTFIELDS, $fields); + + if(defined('PROXY_URL') && !defined('NOPROXY')) { + curl_setopt($ch, CURLOPT_PROXY, PROXY_URL); + } + + curl_setopt($ch, CURLOPT_HEADER, true); + curl_setopt($ch, CURLINFO_HEADER_OUT, true); + + $data = curl_exec($ch); + + $errorCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + + $curlError = curl_error($ch); + $curlErrno = curl_errno($ch); + $curlInfo = curl_getinfo($ch); + + if($data === false) + fDebug::log("Cant't download {$url} cUrl error: {$curlError} ({$curlErrno})"); + + curl_close($ch); + + if($errorCode != 200) { + returnServerError(error_get_last()); + } else { + preg_match_all('/^Set-Cookie:\s*([^;]*)/mi', $data, $matches); + $cookies = array(); + + foreach($matches[1] as $item) { + parse_str($item, $cookie); + $cookies = array_merge($cookies, $cookie); + } + + return $cookies; + } + } +} diff --git a/bridges/GQMagazineBridge.php b/bridges/GQMagazineBridge.php index 2884ab6..14a9a56 100644 --- a/bridges/GQMagazineBridge.php +++ b/bridges/GQMagazineBridge.php @@ -117,7 +117,7 @@ class GQMagazineBridge extends BridgeAbstract */ private function loadFullArticle($uri){ $html = getSimpleHTMLDOMCached($uri); - return $html->find('section[data-test-id=ArticleBodyContent]', 0); + return $html->find('section[data-test-id=MainContentWrapper]', 0); } /** diff --git a/bridges/GiphyBridge.php b/bridges/GiphyBridge.php index 26d1eba..202bbbb 100644 --- a/bridges/GiphyBridge.php +++ b/bridges/GiphyBridge.php @@ -5,7 +5,7 @@ class GiphyBridge extends BridgeAbstract { const MAINTAINER = 'kraoc'; const NAME = 'Giphy Bridge'; - const URI = 'http://giphy.com/'; + const URI = 'https://giphy.com/'; const CACHE_TIMEOUT = 300; //5min const DESCRIPTION = 'Bridge for giphy.com'; diff --git a/bridges/GoogleSearchBridge.php b/bridges/GoogleSearchBridge.php index c3d9561..e02aaeb 100644 --- a/bridges/GoogleSearchBridge.php +++ b/bridges/GoogleSearchBridge.php @@ -25,13 +25,10 @@ class GoogleSearchBridge extends BridgeAbstract { public function collectData(){ $html = ''; - $html = getSimpleHTMLDOM(self::URI - . 'search?q=' - . urlencode($this->getInput('q')) - . '&num=100&complete=0&tbs=qdr:y,sbd:1') + $html = getSimpleHTMLDOM($this->getURI()) or returnServerError('No results for this query.'); - $emIsRes = $html->find('div[id=ires]', 0); + $emIsRes = $html->find('div[id=res]', 0); if(!is_null($emIsRes)) { foreach($emIsRes->find('div[class=g]') as $element) { @@ -54,6 +51,17 @@ class GoogleSearchBridge extends BridgeAbstract { } } + public function getURI() { + if (!is_null($this->getInput('q'))) { + return self::URI + . 'search?q=' + . urlencode($this->getInput('q')) + . '&num=100&complete=0&tbs=qdr:y,sbd:1'; + } + + return parent::getURI(); + } + public function getName(){ if(!is_null($this->getInput('q'))) { return $this->getInput('q') . ' - Google search'; diff --git a/bridges/HDWallpapersBridge.php b/bridges/HDWallpapersBridge.php index f1579e0..16c08e7 100644 --- a/bridges/HDWallpapersBridge.php +++ b/bridges/HDWallpapersBridge.php @@ -2,7 +2,7 @@ class HDWallpapersBridge extends BridgeAbstract { const MAINTAINER = 'nel50n'; const NAME = 'HD Wallpapers Bridge'; - const URI = 'http://www.hdwallpapers.in/'; + const URI = 'https://www.hdwallpapers.in/'; const CACHE_TIMEOUT = 43200; //12h const DESCRIPTION = 'Returns the latests wallpapers from HDWallpapers'; @@ -72,7 +72,7 @@ class HDWallpapersBridge extends BridgeAbstract { public function getName(){ if(!is_null($this->getInput('c')) && !is_null($this->getInput('r'))) { return 'HDWallpapers - ' - . str_replace(['__', '_'], [' & ', ' '], $this->getInput('c')) + . str_replace(array('__', '_'), array(' & ', ' '), $this->getInput('c')) . ' [' . $this->getInput('r') . ']'; diff --git a/bridges/InstagramBridge.php b/bridges/InstagramBridge.php index 77a48e6..679c4c0 100644 --- a/bridges/InstagramBridge.php +++ b/bridges/InstagramBridge.php @@ -32,11 +32,15 @@ class InstagramBridge extends BridgeAbstract { 'required' => false, 'values' => array( 'All' => 'all', - 'Story' => 'story', 'Video' => 'video', 'Picture' => 'picture', + 'Multiple' => 'multiple', ), 'defaultValue' => 'all' + ), + 'direct_links' => array( + 'name' => 'Use direct media links', + 'type' => 'checkbox', ) ) @@ -44,7 +48,7 @@ class InstagramBridge extends BridgeAbstract { const USER_QUERY_HASH = '58b6785bea111c67129decbe6a448951'; const TAG_QUERY_HASH = '174a5243287c5f3a7de741089750ab3b'; - const STORY_QUERY_HASH = '865589822932d1b43dfe312121dd353a'; + const SHORTCODE_QUERY_HASH = '865589822932d1b43dfe312121dd353a'; protected function getInstagramUserId($username) { @@ -54,7 +58,7 @@ class InstagramBridge extends BridgeAbstract { $cacheFac->setWorkingDir(PATH_LIB_CACHES); $cache = $cacheFac->create(Configuration::getConfig('cache', 'type')); $cache->setScope(get_called_class()); - $cache->setKey([$username]); + $cache->setKey(array($username)); $key = $cache->loadData(); if($key == null) { @@ -75,10 +79,7 @@ class InstagramBridge extends BridgeAbstract { } public function collectData(){ - - if(is_null($this->getInput('u')) && $this->getInput('media_type') == 'story') { - returnClientError('Stories are not supported for hashtags nor locations!'); - } + $directLink = !is_null($this->getInput('direct_links')) && $this->getInput('direct_links'); $data = $this->getInstagramJSON($this->getURI()); @@ -93,22 +94,18 @@ class InstagramBridge extends BridgeAbstract { foreach($userMedia as $media) { $media = $media->node; - if(!is_null($this->getInput('u'))) { - switch($this->getInput('media_type')) { - case 'all': break; - case 'video': - if($media->__typename != 'GraphVideo') continue 2; - break; - case 'picture': - if($media->__typename != 'GraphImage') continue 2; - break; - case 'story': - if($media->__typename != 'GraphSidecar') continue 2; - break; - default: break; - } - } else { - if($this->getInput('media_type') == 'video' && !$media->is_video) continue; + switch($this->getInput('media_type')) { + case 'all': break; + case 'video': + if($media->__typename != 'GraphVideo' || !$media->is_video) continue 2; + break; + case 'picture': + if($media->__typename != 'GraphImage') continue 2; + break; + case 'multiple': + if($media->__typename != 'GraphSidecar') continue 2; + break; + default: break; } $item = array(); @@ -118,69 +115,105 @@ class InstagramBridge extends BridgeAbstract { $item['author'] = $media->owner->username; } - if (isset($media->edge_media_to_caption->edges[0]->node->text)) { - $textContent = $media->edge_media_to_caption->edges[0]->node->text; - } else { - $textContent = '(no text)'; - } + $textContent = $this->getTextContent($media); - $item['title'] = ($media->is_video ? '▶ ' : '') . trim($textContent); + $item['title'] = ($media->is_video ? '▶ ' : '') . $textContent; $titleLinePos = strpos(wordwrap($item['title'], 120), "\n"); if ($titleLinePos != false) { $item['title'] = substr($item['title'], 0, $titleLinePos) . '...'; } - if(!is_null($this->getInput('u')) && $media->__typename == 'GraphSidecar') { - - $data = $this->getInstagramStory($item['uri']); - $item['content'] = $data[0]; - $item['enclosures'] = $data[1]; - } else { - $mediaURI = self::URI . 'p/' . $media->shortcode . '/media?size=l'; - $item['content'] = '<a href="' . htmlentities($item['uri']) . '" target="_blank">'; - $item['content'] .= '<img src="' . htmlentities($mediaURI) . '" alt="' . $item['title'] . '" />'; - $item['content'] .= '</a><br><br>' . nl2br(htmlentities($textContent)); - $item['enclosures'] = array($mediaURI); + switch($media->__typename) { + case 'GraphSidecar': + $data = $this->getInstagramSidecarData($item['uri'], $item['title']); + $item['content'] = $data[0]; + $item['enclosures'] = $data[1]; + break; + case 'GraphImage': + if($directLink) { + $mediaURI = $media->display_url; + } else { + $mediaURI = self::URI . 'p/' . $media->shortcode . '/media?size=l'; + } + $item['content'] = '<a href="' . htmlentities($item['uri']) . '" target="_blank">'; + $item['content'] .= '<img src="' . htmlentities($mediaURI) . '" alt="' . $item['title'] . '" />'; + $item['content'] .= '</a><br><br>' . nl2br(htmlentities($textContent)); + $item['enclosures'] = array($mediaURI); + break; + case 'GraphVideo': + $data = $this->getInstagramVideoData($item['uri']); + $item['content'] = $data[0]; + if($directLink) { + $item['enclosures'] = $data[1]; + } else { + $item['enclosures'] = array(self::URI . 'p/' . $media->shortcode . '/media?size=l'); + } + break; + default: break; } - $item['timestamp'] = $media->taken_at_timestamp; $this->items[] = $item; } } - protected function getInstagramStory($uri) { - - $shortcode = explode('/', $uri)[4]; - $data = getContents(self::URI . - 'graphql/query/?query_hash=' . - self::STORY_QUERY_HASH . - '&variables={"shortcode"%3A"' . - $shortcode . - '"}'); + // returns Sidecar(a post which has multiple media)'s contents and enclosures + protected function getInstagramSidecarData($uri, $postTitle) { + $mediaInfo = $this->getSinglePostData($uri); - $mediaInfo = json_decode($data)->data->shortcode_media; + $textContent = $this->getTextContent($mediaInfo); - //Process the first element, that isn't in the node graph - if (count($mediaInfo->edge_media_to_caption->edges) > 0) { - $caption = $mediaInfo->edge_media_to_caption->edges[0]->node->text; - } else { - $caption = ''; + $enclosures = array(); + $content = ''; + foreach($mediaInfo->edge_sidecar_to_children->edges as $singleMedia) { + $singleMedia = $singleMedia->node; + if($singleMedia->is_video) { + if(in_array($singleMedia->video_url, $enclosures)) continue; // check if not added yet + $content .= '<video controls><source src="' . $singleMedia->video_url . '" type="video/mp4"></video><br>'; + array_push($enclosures, $singleMedia->video_url); + } else { + if(in_array($singleMedia->display_url, $enclosures)) continue; // check if not added yet + $content .= '<a href="' . $singleMedia->display_url . '" target="_blank">'; + $content .= '<img src="' . $singleMedia->display_url . '" alt="' . $postTitle . '" />'; + $content .= '</a><br>'; + array_push($enclosures, $singleMedia->display_url); + } } + $content .= '<br>' . nl2br(htmlentities($textContent)); - $enclosures = [$mediaInfo->display_url]; - $content = '<img src="' . htmlentities($mediaInfo->display_url) . '" alt="' . $caption . '" />'; + return array($content, $enclosures); + } - foreach($mediaInfo->edge_sidecar_to_children->edges as $media) { - $display_url = $media->node->display_url; - if(!in_array($display_url, $enclosures)) { // add only if not added yet - $content .= '<img src="' . htmlentities($display_url) . '" alt="' . $caption . '" />'; - $enclosures[] = $display_url; - } + // returns Video post's contents and enclosures + protected function getInstagramVideoData($uri) { + $mediaInfo = $this->getSinglePostData($uri); + + $textContent = $this->getTextContent($mediaInfo); + $content = '<video controls><source src="' . $mediaInfo->video_url . '" type="video/mp4"></video><br>'; + $content .= '<br>' . nl2br(htmlentities($textContent)); + + return array($content, array($mediaInfo->video_url)); + } + + protected function getTextContent($media) { + $textContent = '(no text)'; + //Process the first element, that isn't in the node graph + if (count($media->edge_media_to_caption->edges) > 0) { + $textContent = trim($media->edge_media_to_caption->edges[0]->node->text); } + return $textContent; + } - return [$content, $enclosures]; + protected function getSinglePostData($uri) { + $shortcode = explode('/', $uri)[4]; + $data = getContents(self::URI . + 'graphql/query/?query_hash=' . + self::SHORTCODE_QUERY_HASH . + '&variables={"shortcode"%3A"' . + $shortcode . + '"}'); + return json_decode($data)->data->shortcode_media; } protected function getInstagramJSON($uri) { diff --git a/bridges/JapanExpoBridge.php b/bridges/JapanExpoBridge.php index 1790171..7906ec0 100644 --- a/bridges/JapanExpoBridge.php +++ b/bridges/JapanExpoBridge.php @@ -19,28 +19,6 @@ class JapanExpoBridge extends BridgeAbstract { public function collectData(){ - function frenchPubDateToTimestamp($date_to_parse) { - return strtotime( - strtr( - strtolower(str_replace('Publié le ', '', $date_to_parse)), - array( - 'janvier' => 'jan', - 'février' => 'feb', - 'mars' => 'march', - 'avril' => 'apr', - 'mai' => 'may', - 'juin' => 'jun', - 'juillet' => 'jul', - 'août' => 'aug', - 'septembre' => 'sep', - 'octobre' => 'oct', - 'novembre' => 'nov', - 'décembre' => 'dec' - ) - ) - ); - } - $convert_article_images = function($matches){ if(is_array($matches) && count($matches) > 1) { return '<img src="' . $matches[1] . '" />'; @@ -82,7 +60,7 @@ class JapanExpoBridge extends BridgeAbstract { $content = $headings . $article; } else { $date_text = $element->find('span.date', 0)->plaintext; - $timestamp = frenchPubDateToTimestamp($date_text); + $timestamp = $this->frenchPubDateToTimestamp($date_text); $title = trim($element->find('span._title', 0)->plaintext); $content = '<img src="' . $thumbnail @@ -103,4 +81,26 @@ class JapanExpoBridge extends BridgeAbstract { $count++; } } + + private function frenchPubDateToTimestamp($date_to_parse) { + return strtotime( + strtr( + strtolower(str_replace('Publié le ', '', $date_to_parse)), + array( + 'janvier' => 'jan', + 'février' => 'feb', + 'mars' => 'march', + 'avril' => 'apr', + 'mai' => 'may', + 'juin' => 'jun', + 'juillet' => 'jul', + 'août' => 'aug', + 'septembre' => 'sep', + 'octobre' => 'oct', + 'novembre' => 'nov', + 'décembre' => 'dec' + ) + ) + ); + } } diff --git a/bridges/KonachanBridge.php b/bridges/KonachanBridge.php index 4250e8b..2aada37 100644 --- a/bridges/KonachanBridge.php +++ b/bridges/KonachanBridge.php @@ -5,7 +5,7 @@ class KonachanBridge extends MoebooruBridge { const MAINTAINER = 'mitsukarenai'; const NAME = 'Konachan'; - const URI = 'http://konachan.com/'; + const URI = 'https://konachan.com/'; const DESCRIPTION = 'Returns images from given page'; } diff --git a/bridges/KununuBridge.php b/bridges/KununuBridge.php index 7cc4af6..e26292d 100644 --- a/bridges/KununuBridge.php +++ b/bridges/KununuBridge.php @@ -34,6 +34,12 @@ class KununuBridge extends BridgeAbstract { 'name' => 'Include benefits', 'type' => 'checkbox', 'title' => 'Activate to include benefits in the feed' + ), + 'limit' => array( + 'name' => 'Limit', + 'type' => 'number', + 'defaultValue' => 3, + 'title' => "Maximum number of items to return in the feed.\n0 = unlimited" ) ), array( @@ -108,6 +114,8 @@ class KununuBridge extends BridgeAbstract { $articles = $section->find('article') or returnServerError('Unable to find articles!'); + $limit = $this->getInput('limit') ?: 0; + // Go through all articles foreach($articles as $article) { @@ -141,6 +149,8 @@ class KununuBridge extends BridgeAbstract { $this->items[] = $item; + if ($limit > 0 && count($this->items) >= $limit) break; + } } diff --git a/bridges/LeBonCoinBridge.php b/bridges/LeBonCoinBridge.php index 519fc91..fc1432e 100644 --- a/bridges/LeBonCoinBridge.php +++ b/bridges/LeBonCoinBridge.php @@ -431,11 +431,11 @@ class LeBonCoinBridge extends BridgeAbstract { ); if($this->getInput('region') != '') { - $requestJson->filters->location['regions'] = [$this->getInput('region')]; + $requestJson->filters->location['regions'] = array($this->getInput('region')); } if($this->getInput('department') != '') { - $requestJson->filters->location['departments'] = [$this->getInput('department')]; + $requestJson->filters->location['departments'] = array($this->getInput('department')); } if($this->getInput('cities') != '') { @@ -467,7 +467,7 @@ class LeBonCoinBridge extends BridgeAbstract { } if($this->getInput('estate') != '') { - $requestJson->filters->enums['real_estate_type'] = [$this->getInput('estate')]; + $requestJson->filters->enums['real_estate_type'] = array($this->getInput('estate')); } if($this->getInput('roomsmin') != '' @@ -526,7 +526,7 @@ class LeBonCoinBridge extends BridgeAbstract { } if($this->getInput('fuel') != '') { - $requestJson->filters->enums['fuel'] = [$this->getInput('fuel')]; + $requestJson->filters->enums['fuel'] = array($this->getInput('fuel')); } $requestJson->limit = 30; diff --git a/bridges/ListverseBridge.php b/bridges/ListverseBridge.php new file mode 100644 index 0000000..f597c0b --- /dev/null +++ b/bridges/ListverseBridge.php @@ -0,0 +1,22 @@ +<?php +class ListverseBridge extends FeedExpander { + + const MAINTAINER = 'IceWreck'; + const NAME = 'Listverse Bridge'; + const URI = 'https://listverse.com/'; + const CACHE_TIMEOUT = 3600; + const DESCRIPTION = 'RSS feed for Listverse'; + + public function collectData(){ + $this->collectExpandableDatas('https://listverse.com/feed/', 15); + } + + protected function parseItem($newsItem){ + $item = parent::parseItem($newsItem); + // $articlePage gets the entire page's contents + $articlePage = getSimpleHTMLDOM($newsItem->link); + $article = $articlePage->find('#articlecontentonly', 0); + $item['content'] = $article; + return $item; + } +} diff --git a/bridges/MangareaderBridge.php b/bridges/MangareaderBridge.php index 9ecb0fe..a41113a 100644 --- a/bridges/MangareaderBridge.php +++ b/bridges/MangareaderBridge.php @@ -3,7 +3,7 @@ class MangareaderBridge extends BridgeAbstract { const MAINTAINER = 'logmanoriginal'; const NAME = 'Mangareader Bridge'; - const URI = 'http://www.mangareader.net'; + const URI = 'https://www.mangareader.net'; const CACHE_TIMEOUT = 10800; // 3h const DESCRIPTION = 'Returns the latest updates, popular mangas or manga updates (new chapters)'; diff --git a/bridges/MediapartBridge.php b/bridges/MediapartBridge.php index 15d1d3e..f7fff4a 100644 --- a/bridges/MediapartBridge.php +++ b/bridges/MediapartBridge.php @@ -30,29 +30,34 @@ class MediapartBridge extends FeedExpander { protected function parseItem($newsItem) { $item = parent::parseItem($newsItem); - // Enable single page mode? - if ($this->getInput('single_page_mode') === true) { - $item['uri'] .= '?onglet=full'; - } + // Mediapart provide multiple type of contents. + // We only process items relative to the newspaper + // See issue #1292 - https://github.com/RSS-Bridge/rss-bridge/issues/1292 + if (strpos($item['uri'], self::URI . 'journal/') === 0) { + // Enable single page mode? + if ($this->getInput('single_page_mode') === true) { + $item['uri'] .= '?onglet=full'; + } + + // If a session cookie is defined, get the full article + $mpsessid = $this->getInput('mpsessid'); + if (!empty($mpsessid)) { + // Set the session cookie + $opt = array(); + $opt[CURLOPT_COOKIE] = 'MPSESSID=' . $mpsessid; + + // Get the page + $articlePage = getSimpleHTMLDOM( + $newsItem->link . '?onglet=full', + array(), + $opt); - // If a session cookie is defined, get the full article - $mpsessid = $this->getInput('mpsessid'); - if (!empty($mpsessid)) { - // Set the session cookie - $opt = array(); - $opt[CURLOPT_COOKIE] = 'MPSESSID=' . $mpsessid; - - // Get the page - $articlePage = getSimpleHTMLDOM( - $newsItem->link . '?onglet=full', - array(), - $opt); - - // Extract the article content - $content = $articlePage->find('div.content-article', 0)->innertext; - $content = sanitize($content); - $content = defaultLinkTo($content, static::URI); - $item['content'] .= $content; + // Extract the article content + $content = $articlePage->find('div.content-article', 0)->innertext; + $content = sanitize($content); + $content = defaultLinkTo($content, static::URI); + $item['content'] .= $content; + } } return $item; diff --git a/bridges/N26Bridge.php b/bridges/N26Bridge.php index dd1c423..ac43756 100644 --- a/bridges/N26Bridge.php +++ b/bridges/N26Bridge.php @@ -15,11 +15,11 @@ class N26Bridge extends BridgeAbstract public function collectData() { - $html = getSimpleHTMLDOM(self::URI . '/en-fr/blog-archive') + $html = getSimpleHTMLDOM(self::URI . '/en-eu/blog-archive') or returnServerError('Error while downloading the website content'); - foreach($html->find('div.ga') as $article) { - $item = []; + foreach($html->find('div[class="ag ah ai aj bs bt dx ea fo gx ie if ih ii ij ik s"]') as $article) { + $item = array(); $item['uri'] = self::URI . $article->find('h2 a', 0)->href; $item['title'] = $article->find('h2 a', 0)->plaintext; @@ -27,9 +27,9 @@ class N26Bridge extends BridgeAbstract $fullArticle = getSimpleHTMLDOM($item['uri']) or returnServerError('Error while downloading the full article'); - $dateElement = $fullArticle->find('span[class="fk fl de ch fm by"]', 0); + $dateElement = $fullArticle->find('time', 0); $item['timestamp'] = strtotime($dateElement->plaintext); - $item['content'] = $fullArticle->find('main article', 0)->innertext; + $item['content'] = $fullArticle->find('div[class="af ag ah ai an"]', 1)->innertext; $this->items[] = $item; } diff --git a/bridges/NFLRUSBridge.php b/bridges/NFLRUSBridge.php new file mode 100644 index 0000000..739f4ab --- /dev/null +++ b/bridges/NFLRUSBridge.php @@ -0,0 +1,60 @@ +<?php +class NFLRUSBridge extends BridgeAbstract { + + const NAME = 'NFLRUS'; + const URI = 'http://nflrus.ru/'; + const DESCRIPTION = 'Returns the recent articles published on nflrus.ru'; + const MAINTAINER = 'Maxim Shpak'; + + private function getEnglishMonth($month) { + $months = array( + 'Января' => 'January', + 'Февраля' => 'February', + 'Марта' => 'March', + 'Апреля' => 'April', + 'Мая' => 'May', + 'Июня' => 'June', + 'Июля' => 'July', + 'Августа' => 'August', + 'Сентября' => 'September', + 'Октября' => 'October', + 'Ноября' => 'November', + 'Декабря' => 'December', + ); + + if (isset($months[$month])) { + return $months[$month]; + } + return false; + } + + private function extractArticleTimestamp($article) { + $time = $article->find('time', 0); + if($time) { + $timestring = trim($time->plaintext); + $parts = explode(' ', $timestring); + $month = $this->getEnglishMonth($parts[1]); + if ($month) { + $timestring = $parts[0] . ' ' . $month . ' ' . $parts[2]; + return strtotime($timestring); + } + } + return 0; + } + + public function collectData() { + $html = getSimpleHTMLDOM(self::URI) + or returnServerError('Unable to get any articles from NFLRUS'); + $html = defaultLinkTo($html, self::URI); + + foreach($html->find('article') as $article) { + $item = array(); + $item['uri'] = $article->find('.b-article__title a', 0)->href; + $item['title'] = $article->find('.b-article__title a', 0)->plaintext; + $item['author'] = $article->find('.link-author', 0)->plaintext; + $item['timestamp'] = $this->extractArticleTimestamp($article); + $item['content'] = $article->find('div', 0)->innertext; + $this->items[] = $item; + } + } +} diff --git a/bridges/NiceMatinBridge.php b/bridges/NiceMatinBridge.php index 117c779..b0af760 100644 --- a/bridges/NiceMatinBridge.php +++ b/bridges/NiceMatinBridge.php @@ -3,7 +3,7 @@ class NiceMatinBridge extends FeedExpander { const MAINTAINER = 'pit-fgfjiudghdf'; const NAME = 'NiceMatin'; - const URI = 'http://www.nicematin.com/'; + const URI = 'https://www.nicematin.com/'; const DESCRIPTION = 'Returns the 10 newest posts from NiceMatin (full text)'; public function collectData(){ diff --git a/bridges/NineGagBridge.php b/bridges/NineGagBridge.php index e726c73..939ff38 100644 --- a/bridges/NineGagBridge.php +++ b/bridges/NineGagBridge.php @@ -17,6 +17,15 @@ class NineGagBridge extends BridgeAbstract { 'Fresh' => 'fresh', ), ), + 'video' => array( + 'name' => 'Filter Video', + 'type' => 'list', + 'values' => array( + 'NotFiltred' => 'none', + 'VideoFiltred' => 'without', + 'VideoOnly' => 'only', + ), + ), 'p' => array( 'name' => 'Pages', 'type' => 'number', @@ -121,13 +130,32 @@ class NineGagBridge extends BridgeAbstract { } foreach ($posts as $post) { - $item['uri'] = $post['url']; - $item['title'] = $post['title']; - $item['content'] = self::getContent($post); - $item['categories'] = self::getCategories($post); - $item['timestamp'] = self::getTimestamp($post); + $AvoidElement = false; + switch ($this->getInput('video')) { + case 'without': + if ($post['type'] === 'Animated') { + $AvoidElement = true; + } + break; + case 'only': + echo $post['type']; + if ($post['type'] !== 'Animated') { + $AvoidElement = true; + } + break; + case 'none': default: + break; + } + + if (!$AvoidElement) { + $item['uri'] = $post['url']; + $item['title'] = $post['title']; + $item['content'] = self::getContent($post); + $item['categories'] = self::getCategories($post); + $item['timestamp'] = self::getTimestamp($post); - $this->items[] = $item; + $this->items[] = $item; + } } } diff --git a/bridges/WhydBridge.php b/bridges/OpenwhydBridge.php index 04d0b30..f80cb06 100644 --- a/bridges/WhydBridge.php +++ b/bridges/OpenwhydBridge.php @@ -1,9 +1,9 @@ <?php -class WhydBridge extends BridgeAbstract { +class OpenwhydBridge extends BridgeAbstract { const MAINTAINER = 'kranack'; - const NAME = 'Whyd Bridge'; - const URI = 'http://www.whyd.com/'; + const NAME = 'Openwhyd Bridge'; + const URI = 'https://openwhyd.org'; const CACHE_TIMEOUT = 600; // 10min const DESCRIPTION = 'Returns 10 newest music from user profile'; @@ -17,8 +17,7 @@ class WhydBridge extends BridgeAbstract { private $userName = ''; public function getIcon() { - return self::URI . 'assets/favicons/ -32-6b62a9f14d5e1a9213090d8f00f286bba3a6022381a76390d1d0926493b12593.png?v=6'; + return self::URI . '/images/favicon.ico'; } public function collectData(){ @@ -26,11 +25,11 @@ class WhydBridge extends BridgeAbstract { if(strlen(preg_replace('/[^0-9a-f]/', '', $this->getInput('u'))) == 24) { // is input the userid ? $html = getSimpleHTMLDOM( - self::URI . 'u/' . preg_replace('/[^0-9a-f]/', '', $this->getInput('u')) + self::URI . '/u/' . preg_replace('/[^0-9a-f]/', '', $this->getInput('u')) ) or returnServerError('No results for this query.'); } else { // input may be the username $html = getSimpleHTMLDOM( - self::URI . 'search?q=' . urlencode($this->getInput('u')) + self::URI . '/search?q=' . urlencode($this->getInput('u')) ) or returnServerError('No results for this query.'); for($j = 0; $j < 5; $j++) { @@ -57,6 +56,6 @@ class WhydBridge extends BridgeAbstract { } public function getName(){ - return (!empty($this->userName) ? $this->userName . ' - ' : '') . 'Whyd Bridge'; + return (!empty($this->userName) ? $this->userName . ' - ' : '') . 'Openwhyd Bridge'; } } diff --git a/bridges/ParuVenduImmoBridge.php b/bridges/ParuVenduImmoBridge.php index a2e2b33..7b2825b 100644 --- a/bridges/ParuVenduImmoBridge.php +++ b/bridges/ParuVenduImmoBridge.php @@ -3,7 +3,7 @@ class ParuVenduImmoBridge extends BridgeAbstract { const MAINTAINER = 'polo2ro'; const NAME = 'Paru Vendu Immobilier'; - const URI = 'http://www.paruvendu.fr'; + const URI = 'https://www.paruvendu.fr'; const CACHE_TIMEOUT = 10800; // 3h const DESCRIPTION = 'Returns the ads from the first page of search result.'; diff --git a/bridges/PickyWallpapersBridge.php b/bridges/PickyWallpapersBridge.php index 6c26df7..488b448 100644 --- a/bridges/PickyWallpapersBridge.php +++ b/bridges/PickyWallpapersBridge.php @@ -3,7 +3,7 @@ class PickyWallpapersBridge extends BridgeAbstract { const MAINTAINER = 'nel50n'; const NAME = 'PickyWallpapers Bridge'; - const URI = 'http://www.pickywallpapers.com/'; + const URI = 'https://www.pickywallpapers.com/'; const CACHE_TIMEOUT = 43200; // 12h const DESCRIPTION = 'Returns the latests wallpapers from PickyWallpapers'; diff --git a/bridges/PikabuBridge.php b/bridges/PikabuBridge.php index 987070d..a54f6bf 100644 --- a/bridges/PikabuBridge.php +++ b/bridges/PikabuBridge.php @@ -110,6 +110,10 @@ class PikabuBridge extends BridgeAbstract { } } $img->outertext = '<img src="' . $src . '">'; + + // it is assumed, that img's parents are links to post itself + // we don't need them + $img->parent()->outertext = $img->outertext; } $categories = array(); @@ -125,7 +129,10 @@ class PikabuBridge extends BridgeAbstract { $item['categories'] = $categories; $item['author'] = $post->find('.user__nick', 0)->innertext; $item['title'] = $title->plaintext; - $item['content'] = strip_tags(backgroundToImg($post->find('.story__content-inner', 0)->innertext), '<br><p><img>'); + $item['content'] = strip_tags( + backgroundToImg($post->find('.story__content-inner', 0)->innertext), + '<br><p><img><a> + '); $item['uri'] = $title->href; $item['timestamp'] = strtotime($time->getAttribute('datetime')); $this->items[] = $item; diff --git a/bridges/PinterestBridge.php b/bridges/PinterestBridge.php index 3e51863..48c0cfc 100644 --- a/bridges/PinterestBridge.php +++ b/bridges/PinterestBridge.php @@ -30,7 +30,7 @@ class PinterestBridge extends FeedExpander { private function fixLowRes() { - $newitems = []; + $newitems = array(); $pattern = '/https\:\/\/i\.pinimg\.com\/[a-zA-Z0-9]*x\//'; foreach($this->items as $item) { diff --git a/bridges/PlantUMLReleasesBridge.php b/bridges/PlantUMLReleasesBridge.php new file mode 100644 index 0000000..6648056 --- /dev/null +++ b/bridges/PlantUMLReleasesBridge.php @@ -0,0 +1,67 @@ +<?php + +/** + * PlantUML releases bridge showing latest releases content + * @author nicolas-delsaux + * + */ +class PlantUMLReleasesBridge extends BridgeAbstract +{ + const MAINTAINER = 'Riduidel'; + + const NAME = 'PlantUML Releases'; + + const AUTHOR = 'PlantUML team'; + + // URI is no more valid, since we can address the whole gq galaxy + const URI = 'http://plantuml.com/fr/changes'; + + const CACHE_TIMEOUT = 7200; // 2h + const DESCRIPTION = 'PlantUML releases bridge, showing for each release the changelog'; + + const DEFAULT_DOMAIN = 'plantuml.com'; + + const PARAMETERS = array( array( + )); + + const REPLACED_ATTRIBUTES = array( + 'href' => 'href', + 'src' => 'src', + 'data-original' => 'src' + ); + + private function getDomain() { + $domain = $this->getInput('domain'); + if (empty($domain)) + $domain = self::DEFAULT_DOMAIN; + if (strpos($domain, '://') === false) + $domain = 'https://' . $domain; + return $domain; + } + + public function getURI() + { + return self::URI; + } + + public function collectData() + { + $html = getSimpleHTMLDOM($this->getURI()) or returnServerError('Could not request ' . $this->getURI()); + + // Since GQ don't want simple class scrapping, let's do it the hard way and ... discover content ! + $main = $html->find('div[id=root]', 0); + foreach ($main->find('h2') as $release) { + $item = array(); + $item['author'] = self::AUTHOR; + $release_text = $release->innertext; + if (preg_match('/(.+) \((.*)\)/', $release_text, $matches)) { + $item['title'] = $matches[1]; + // And now, build the date from the date text + $item['timestamp'] = strtotime($matches[2]); + } + $item['uri'] = $this->getURI(); + $item['content'] = $release->next_sibling (); + $this->items[] = $item; + } + } +} diff --git a/bridges/ReadComicsBridge.php b/bridges/ReadComicsBridge.php deleted file mode 100644 index 739e6cc..0000000 --- a/bridges/ReadComicsBridge.php +++ /dev/null @@ -1,44 +0,0 @@ -<?php -class ReadComicsBridge extends BridgeAbstract { - - const MAINTAINER = 'niawag'; - const NAME = 'Read Comics'; - const URI = 'http://www.readcomics.tv/'; - const DESCRIPTION = 'Enter the comics as they appear in the website uri, - separated by semicolons, ex: good-comic-1;good-comic-2; ...'; - - const PARAMETERS = array( array( - 'q' => array( - 'name' => 'keywords, separated by semicolons', - 'exampleValue' => 'first list;second list;...', - 'required' => true - ), - )); - - public function collectData(){ - - function parseDateTimestamp($element){ - $guessedDate = $element->find('span', 0)->plaintext; - $guessedDate = strptime($guessedDate, '%m/%d/%Y'); - $timestamp = mktime(0, 0, 0, $guessedDate['tm_mon'] + 1, $guessedDate['tm_mday'], date('Y')); - - return $timestamp; - } - - $keywordsList = explode(';', $this->getInput('q')); - foreach($keywordsList as $keywords) { - $html = $this->getSimpleHTMLDOM(self::URI . 'comic/' . rawurlencode($keywords)) - or $this->returnServerError('Could not request readcomics.tv.'); - - foreach($html->find('li') as $element) { - $item = array(); - $item['uri'] = $element->find('a.ch-name', 0)->href; - $item['id'] = $item['uri']; - $item['timestamp'] = parseDateTimestamp($element); - $item['title'] = $element->find('a.ch-name', 0)->plaintext; - if(isset($item['title'])) - $this->items[] = $item; - } - } - } -} diff --git a/bridges/RedditBridge.php b/bridges/RedditBridge.php new file mode 100644 index 0000000..d83c0a3 --- /dev/null +++ b/bridges/RedditBridge.php @@ -0,0 +1,40 @@ +<?php +class RedditBridge extends FeedExpander { + + const MAINTAINER = 'leomaradan'; + const NAME = 'Reddit Bridge'; + const URI = 'https://www.reddit.com/'; + const DESCRIPTION = 'Reddit RSS Feed fixer'; + + const PARAMETERS = array( + 'single' => array( + 'r' => array( + 'name' => 'SubReddit', + 'required' => true, + 'exampleValue' => 'selfhosted', + 'title' => 'SubReddit name' + ) + ), + 'multi' => array( + 'rs' => array( + 'name' => 'SubReddits', + 'required' => true, + 'exampleValue' => 'selfhosted, php', + 'title' => 'SubReddit names, separated by commas' + ) + ) + ); + + public function collectData(){ + + switch($this->queriedcontext) { + case 'single': $subreddits[] = $this->getInput('r'); break; + case 'multi': $subreddits = explode(',', $this->getInput('rs')); break; + } + + foreach ($subreddits as $subreddit) { + $name = trim($subreddit); + $this->collectExpandableDatas("https://www.reddit.com/r/$name/.rss"); + } + } +} diff --git a/bridges/Releases3DSBridge.php b/bridges/Releases3DSBridge.php index 6c159d1..fe2df8e 100644 --- a/bridges/Releases3DSBridge.php +++ b/bridges/Releases3DSBridge.php @@ -9,22 +9,6 @@ class Releases3DSBridge extends BridgeAbstract { public function collectData(){ - function typeToString($type){ - switch($type) { - case 1: return '3DS Game'; - case 4: return 'eShop'; - default: return '??? (' . $type . ')'; - } - } - - function cardToString($card){ - switch($card) { - case 1: return 'Regular (CARD1)'; - case 2: return 'NAND (CARD2)'; - default: return '??? (' . $card . ')'; - } - } - $dataUrl = self::URI . 'xml.php'; $xml = getContents($dataUrl) or returnServerError('Could not request 3dsdb: ' . $dataUrl); @@ -95,8 +79,8 @@ class Releases3DSBridge extends BridgeAbstract { . '<br /><b>Release Name: </b>' . $releasename . '<br /><b>Trimmed size: </b>' . intval(intval($trimmedsize) / 1048576) . 'MB<br /><b>Firmware: </b>' . $firmware - . '<br /><b>Type: </b>' . typeToString($type) - . '<br /><b>Card: </b>' . cardToString($card) + . '<br /><b>Type: </b>' . $this->typeToString($type) + . '<br /><b>Card: </b>' . $this->cardToString($card) . '<br />'; //Build search links section to facilitate release search using search engines @@ -124,4 +108,20 @@ class Releases3DSBridge extends BridgeAbstract { $limit++; } } + + private function typeToString($type){ + switch($type) { + case 1: return '3DS Game'; + case 4: return 'eShop'; + default: return '??? (' . $type . ')'; + } + } + + private function cardToString($card){ + switch($card) { + case 1: return 'Regular (CARD1)'; + case 2: return 'NAND (CARD2)'; + default: return '??? (' . $card . ')'; + } + } } diff --git a/bridges/ReporterreBridge.php b/bridges/ReporterreBridge.php index 438c55b..41f0f70 100644 --- a/bridges/ReporterreBridge.php +++ b/bridges/ReporterreBridge.php @@ -3,7 +3,7 @@ class ReporterreBridge extends BridgeAbstract { const MAINTAINER = 'nyutag'; const NAME = 'Reporterre Bridge'; - const URI = 'http://www.reporterre.net/'; + const URI = 'https://www.reporterre.net/'; const DESCRIPTION = 'Returns the newest articles.'; private function extractContent($url){ diff --git a/bridges/RevolutBridge.php b/bridges/RevolutBridge.php new file mode 100644 index 0000000..04ca377 --- /dev/null +++ b/bridges/RevolutBridge.php @@ -0,0 +1,81 @@ +<?php + +class RevolutBridge extends BridgeAbstract { + + const NAME = 'Revolut Blog'; + const URI = 'https://blog.revolut.com/'; + const DESCRIPTION = 'Returns recent blog posts from Revolut.'; + const MAINTAINER = 'dominik-th'; + + public function getIcon() { + return self::URI . 'favicon.png'; + } + + public function collectData() { + $articleOverview = getSimpleHTMLDOM(self::URI . 'sitemap-posts.xml') + or returnServerError('Error while downloading the website content'); + + $articles = array_slice($articleOverview->find('url'), 0, 15); + + foreach($articles as $article) { + $item = array(); + + $item['uri'] = $article->find('loc', 0)->plaintext; + $item['timestamp'] = $article->find('lastmod', 0)->plaintext; + $item['enclosures'] = array( + $article->find('image:loc', 0)->plaintext + ); + + $fullArticle = getSimpleHTMLDOMCached($item['uri']) + or returnServerError('Error while downloading the full article'); + + $item['author'] = $fullArticle + ->find('h4[class="author-card-name"] a', 0) + ->plaintext; + $item['title'] = $fullArticle + ->find('h1[class="post-full-title"]', 0) + ->plaintext; + + $content = $fullArticle + ->find('section[class="post-full-content"]', 0); + + foreach($content->find('img') as $image) { + $image->src = $this->generateAbsoluteUrl($image->src); + } + + foreach($content->find('a') as $hyperlink) { + $hyperlink->href = $this->generateAbsoluteUrl($hyperlink->href); + } + + foreach($content->find('iframe') as $iframe) { + $iframe->outertext = $this->generateYoutubeReplacement($iframe); + } + + $item['content'] = $content->innertext; + $this->items[] = $item; + } + } + + private function generateAbsoluteUrl($path) { + if (filter_var($path, FILTER_VALIDATE_URL)) { + return $path; + } else { + return self::URI . $path; + } + } + + private function generateYoutubeReplacement($iframe) { + $embedUrl = $iframe->src; + if (parse_url($embedUrl, PHP_URL_HOST) === 'www.youtube.com') { + $urlParts = explode('/', parse_url($embedUrl, PHP_URL_PATH)); + $videoId = end($urlParts); + $thumbnailUrl = 'https://img.youtube.com/vi/' . $videoId . '/0.jpg'; + $videoUrl = 'https://www.youtube.com/watch?v=' . $videoId; + $videoReplacement = str_get_html('<a><img /></a>'); + $videoReplacement->find('a', 0)->href = $videoUrl; + $videoReplacement->find('img', 0)->src = $thumbnailUrl; + return $videoReplacement; + } + return $iframe->outertext; + } +} diff --git a/bridges/RoadAndTrackBridge.php b/bridges/RoadAndTrackBridge.php index b3f0acc..22ec8b5 100644 --- a/bridges/RoadAndTrackBridge.php +++ b/bridges/RoadAndTrackBridge.php @@ -25,7 +25,7 @@ class RoadAndTrackBridge extends BridgeAbstract { private function fixImages($content) { - $enclosures = []; + $enclosures = array(); foreach($content->find('img') as $image) { $image->src = explode('?', $image->getAttribute('data-src'))[0]; $enclosures[] = $image->src; diff --git a/bridges/Rule34Bridge.php b/bridges/Rule34Bridge.php index b46ec00..71f48c6 100644 --- a/bridges/Rule34Bridge.php +++ b/bridges/Rule34Bridge.php @@ -5,7 +5,7 @@ class Rule34Bridge extends GelbooruBridge { const MAINTAINER = 'mitsukarenai'; const NAME = 'Rule34'; - const URI = 'http://rule34.xxx/'; + const URI = 'https://rule34.xxx/'; const DESCRIPTION = 'Returns images from given page'; const PIDBYPAGE = 50; diff --git a/bridges/Rule34pahealBridge.php b/bridges/Rule34pahealBridge.php index d130d36..0e13ed0 100644 --- a/bridges/Rule34pahealBridge.php +++ b/bridges/Rule34pahealBridge.php @@ -5,7 +5,7 @@ class Rule34pahealBridge extends Shimmie2Bridge { const MAINTAINER = 'mitsukarenai'; const NAME = 'Rule34paheal'; - const URI = 'http://rule34.paheal.net/'; + const URI = 'https://rule34.paheal.net/'; const DESCRIPTION = 'Returns images from given page'; protected function getItemFromElement($element){ diff --git a/bridges/SafebooruBridge.php b/bridges/SafebooruBridge.php index d95e557..98da692 100644 --- a/bridges/SafebooruBridge.php +++ b/bridges/SafebooruBridge.php @@ -5,7 +5,7 @@ class SafebooruBridge extends GelbooruBridge { const MAINTAINER = 'mitsukarenai'; const NAME = 'Safebooru'; - const URI = 'http://safebooru.org/'; + const URI = 'https://safebooru.org/'; const DESCRIPTION = 'Returns images from given page'; const PIDBYPAGE = 40; diff --git a/bridges/ScmbBridge.php b/bridges/ScmbBridge.php index 2107aa3..e8d7f51 100644 --- a/bridges/ScmbBridge.php +++ b/bridges/ScmbBridge.php @@ -3,7 +3,7 @@ class ScmbBridge extends BridgeAbstract { const MAINTAINER = 'Astalaseven'; const NAME = 'Se Coucher Moins Bête Bridge'; - const URI = 'http://secouchermoinsbete.fr'; + const URI = 'https://secouchermoinsbete.fr'; const CACHE_TIMEOUT = 21600; // 6h const DESCRIPTION = 'Returns the newest anecdotes.'; diff --git a/bridges/ScoopItBridge.php b/bridges/ScoopItBridge.php index 997837d..ba586fa 100644 --- a/bridges/ScoopItBridge.php +++ b/bridges/ScoopItBridge.php @@ -3,7 +3,7 @@ class ScoopItBridge extends BridgeAbstract { const MAINTAINER = 'Pitchoule'; const NAME = 'ScoopIt'; - const URI = 'http://www.scoop.it/'; + const URI = 'https://www.scoop.it/'; const CACHE_TIMEOUT = 21600; // 6h const DESCRIPTION = 'Returns most recent results from ScoopIt.'; diff --git a/bridges/Shimmie2Bridge.php b/bridges/Shimmie2Bridge.php index 9923514..fdc97f4 100644 --- a/bridges/Shimmie2Bridge.php +++ b/bridges/Shimmie2Bridge.php @@ -4,7 +4,7 @@ require_once('DanbooruBridge.php'); class Shimmie2Bridge extends DanbooruBridge { const NAME = 'Shimmie v2'; - const URI = 'http://shimmie.shishnet.org/v2/'; + const URI = 'https://shimmie.shishnet.org/v2/'; const DESCRIPTION = 'Returns images from given page'; const PATHTODATA = '.shm-thumb-link'; diff --git a/bridges/SoundcloudBridge.php b/bridges/SoundcloudBridge.php index 8938ff9..9607d33 100644 --- a/bridges/SoundcloudBridge.php +++ b/bridges/SoundcloudBridge.php @@ -1,7 +1,7 @@ <?php class SoundCloudBridge extends BridgeAbstract { - const MAINTAINER = 'kranack'; + const MAINTAINER = 'kranack, Roliga'; const NAME = 'Soundcloud Bridge'; const URI = 'https://soundcloud.com/'; const CACHE_TIMEOUT = 600; // 10min @@ -14,27 +14,18 @@ class SoundCloudBridge extends BridgeAbstract { ) )); - const CLIENT_ID = 'W0KEWWILAjDiRH89X0jpwzuq6rbSK08R'; - private $feedIcon = null; + private $clientIDCache = null; public function collectData(){ - - $res = json_decode(getContents( - 'https://api.soundcloud.com/resolve?url=http://www.soundcloud.com/' - . urlencode($this->getInput('u')) - . '&client_id=' - . self::CLIENT_ID + $res = $this->apiGet('resolve', array( + 'url' => 'http://www.soundcloud.com/' . $this->getInput('u') )) or returnServerError('No results for this query'); $this->feedIcon = $res->avatar_url; - $tracks = json_decode(getContents( - 'https://api.soundcloud.com/users/' - . urlencode($res->id) - . '/tracks?client_id=' - . self::CLIENT_ID - )) or returnServerError('No results for this user'); + $tracks = $this->apiGet('users/' . urlencode($res->id) . '/tracks') + or returnServerError('No results for this user'); $numTracks = min(count($tracks), 10); for($i = 0; $i < $numTracks; $i++) { @@ -45,7 +36,7 @@ class SoundCloudBridge extends BridgeAbstract { $item['content'] = $tracks[$i]->description; $item['enclosures'] = array($tracks[$i]->uri . '/stream?client_id=' - . self::CLIENT_ID); + . $this->getClientID()); $item['id'] = self::URI . urlencode($this->getInput('u')) @@ -75,4 +66,68 @@ class SoundCloudBridge extends BridgeAbstract { return parent::getName(); } + + private function initClientIDCache(){ + if($this->clientIDCache !== null) + return; + + $cacheFac = new CacheFactory(); + $cacheFac->setWorkingDir(PATH_LIB_CACHES); + $this->clientIDCache = $cacheFac->create(Configuration::getConfig('cache', 'type')); + $this->clientIDCache->setScope(get_called_class()); + $this->clientIDCache->setKey(array('client_id')); + } + + private function getClientID(){ + $this->initClientIDCache(); + + $clientID = $this->clientIDCache->loadData(); + + if($clientID == null) { + return $this->refreshClientID(); + } else { + return $clientID; + } + } + + private function refreshClientID(){ + $this->initClientIDCache(); + + // Without url=http, this returns a 404 + $playerHTML = getContents('https://w.soundcloud.com/player/?url=http') + or returnServerError('Unable to get player page.'); + $regex = '/widget-.+?\.js/'; + if(preg_match($regex, $playerHTML, $matches) == false) + returnServerError('Unable to find widget JS URL.'); + $widgetURL = 'https://widget.sndcdn.com/' . $matches[0]; + + $widgetJS = getContents($widgetURL) + or returnServerError('Unable to get widget JS page.'); + $regex = '/client_id.*?"(.+?)"/'; + if(preg_match($regex, $widgetJS, $matches) == false) + returnServerError('Unable to find client ID.'); + $clientID = $matches[1]; + + $this->clientIDCache->saveData($clientID); + return $clientID; + } + + private function buildAPIURL($endpoint, $parameters){ + return 'https://api.soundcloud.com/' + . $endpoint + . '?' + . http_build_query($parameters); + } + + private function apiGet($endpoint, $parameters = array()){ + $parameters['client_id'] = $this->getClientID(); + + try { + return json_decode(getContents($this->buildAPIURL($endpoint, $parameters))); + } catch (Exception $e) { + // Retry once with refreshed client ID + $parameters['client_id'] = $this->refreshClientID(); + return json_decode(getContents($this->buildAPIURL($endpoint, $parameters))); + } + } } diff --git a/bridges/StoriesIGBridge.php b/bridges/StoriesIGBridge.php index ddf9846..9b5f7cb 100644 --- a/bridges/StoriesIGBridge.php +++ b/bridges/StoriesIGBridge.php @@ -29,6 +29,7 @@ class StoriesIGBridge extends BridgeAbstract { $item['title'] = $this->getInput('username') . ' story'; $item['uri'] = $result->find('div.download', 0)->find('a', 0)->href; $item['author'] = $this->getInput('username'); + $item['timestamp'] = strtotime($result->find('time', 0)->datetime); $item['uid'] = $result->find('time', 0)->datetime; $item['content'] = $result; @@ -44,4 +45,13 @@ class StoriesIGBridge extends BridgeAbstract { return parent::getURI(); } + + public function getName() { + + if (!is_null($this->getInput('username'))) { + return $this->getInput('username') . ' - ' . self::NAME; + } + + return parent::getName(); + } } diff --git a/bridges/SuperbWallpapersBridge.php b/bridges/SuperbWallpapersBridge.php deleted file mode 100644 index 610dd32..0000000 --- a/bridges/SuperbWallpapersBridge.php +++ /dev/null @@ -1,70 +0,0 @@ -<?php -class SuperbWallpapersBridge extends BridgeAbstract { - - const MAINTAINER = 'nel50n'; - const NAME = 'Superb Wallpapers Bridge'; - const URI = 'http://www.superbwallpapers.com/'; - const CACHE_TIMEOUT = 43200; // 12h - const DESCRIPTION = 'Returns the latests wallpapers from SuperbWallpapers'; - - const PARAMETERS = array( array( - 'c' => array( - 'name' => 'category', - 'required' => true - ), - 'm' => array( - 'name' => 'Max number of wallpapers', - 'type' => 'number' - ), - 'r' => array( - 'name' => 'resolution', - 'exampleValue' => '1920x1200, 1680x1050,…', - 'defaultValue' => '1920x1200' - ) - )); - - public function collectData(){ - $category = $this->getInput('c'); - $resolution = $this->getInput('r'); // Wide wallpaper default - - $num = 0; - $max = $this->getInput('m') ?: 36; - $lastpage = 1; - - // Get last page number - $link = self::URI . '/' . $category . '/9999.html'; - $html = getSimpleHTMLDOM($link) - or returnServerError('Could not load ' . $link); - - $lastpage = min($html->find('.paging .cpage', 0)->innertext(), ceil($max / 36)); - - for($page = 1; $page <= $lastpage; $page++) { - $link = self::URI . '/' . $category . '/' . $page . '.html'; - $html = getSimpleHTMLDOM($link) - or returnServerError('No results for this query.'); - - foreach($html->find('.wpl .i a') as $element) { - $thumbnail = $element->find('img', 0); - - $item = array(); - $item['uri'] = str_replace('200x125', $this->resolution, $thumbnail->src); - $item['timestamp'] = time(); - $item['title'] = $element->title; - $item['content'] = $item['title'] . '<br><a href="' . $item['uri'] . '">' . $thumbnail . '</a>'; - $this->items[] = $item; - - $num++; - if ($num >= $max) - break 2; - } - } - } - - public function getName(){ - if(!is_null($this->getInput('c')) && !is_null($this->getInput('r'))) { - return self::NAME . '- ' . $this->getInput('c') . ' [' . $this->getInput('r') . ']'; - } - - return parent::getName(); - } -} diff --git a/bridges/TbibBridge.php b/bridges/TbibBridge.php index edb761e..819d61e 100644 --- a/bridges/TbibBridge.php +++ b/bridges/TbibBridge.php @@ -5,7 +5,7 @@ class TbibBridge extends GelbooruBridge { const MAINTAINER = 'mitsukarenai'; const NAME = 'Tbib'; - const URI = 'http://tbib.org/'; + const URI = 'https://tbib.org/'; const DESCRIPTION = 'Returns images from given page'; const PIDBYPAGE = 50; diff --git a/bridges/TheCodingLoveBridge.php b/bridges/TheCodingLoveBridge.php index 2a639e3..8060c94 100644 --- a/bridges/TheCodingLoveBridge.php +++ b/bridges/TheCodingLoveBridge.php @@ -3,7 +3,7 @@ class TheCodingLoveBridge extends BridgeAbstract { const MAINTAINER = 'superbaillot.net'; const NAME = 'The Coding Love'; - const URI = 'http://thecodinglove.com/'; + const URI = 'https://thecodinglove.com/'; const CACHE_TIMEOUT = 7200; // 2h const DESCRIPTION = 'The Coding Love'; diff --git a/bridges/ThePirateBayBridge.php b/bridges/ThePirateBayBridge.php index 5fc04eb..4b45daf 100644 --- a/bridges/ThePirateBayBridge.php +++ b/bridges/ThePirateBayBridge.php @@ -40,60 +40,6 @@ class ThePirateBayBridge extends BridgeAbstract { public function collectData(){ - function parseDateTimestamp($element){ - $guessedDate = $element->find('font', 0)->plaintext; - $guessedDate = explode('Uploaded ', $guessedDate)[1]; - $guessedDate = explode(',', $guessedDate)[0]; - - if(count(explode(':', $guessedDate)) == 1) { - $guessedDate = strptime($guessedDate, '%m-%d %Y'); - $timestamp = mktime( - 0, - 0, - 0, - $guessedDate['tm_mon'] + 1, - $guessedDate['tm_mday'], - 1900 + $guessedDate['tm_year'] - ); - } elseif(explode(' ', $guessedDate)[0] == 'Today') { - $guessedDate = strptime( - explode(' ', $guessedDate)[1], '%H:%M' - ); - - $timestamp = mktime( - $guessedDate['tm_hour'], - $guessedDate['tm_min'], - 0, - date('m'), - date('d'), - date('Y') - ); - } elseif(explode(' ', $guessedDate)[0] == 'Y-day') { - $guessedDate = strptime( - explode(' ', $guessedDate)[1], '%H:%M' - ); - - $timestamp = mktime( - $guessedDate['tm_hour'], - $guessedDate['tm_min'], - 0, - date('m', time() - 24 * 60 * 60), - date('d', time() - 24 * 60 * 60), - date('Y', time() - 24 * 60 * 60) - ); - } else { - $guessedDate = strptime($guessedDate, '%m-%d %H:%M'); - $timestamp = mktime( - $guessedDate['tm_hour'], - $guessedDate['tm_min'], - 0, - $guessedDate['tm_mon'] + 1, - $guessedDate['tm_mday'], - date('Y')); - } - return $timestamp; - } - $catBool = $this->getInput('catCheck'); if($catBool) { $catNum = $this->getInput('cat'); @@ -151,7 +97,7 @@ class ThePirateBayBridge extends BridgeAbstract { $item = array(); $item['uri'] = self::URI . $element->find('a.detLink', 0)->href; $item['id'] = self::URI . $element->find('a.detLink', 0)->href; - $item['timestamp'] = parseDateTimestamp($element); + $item['timestamp'] = $this->parseDateTimestamp($element); $item['author'] = $element->find('a.detDesc', 0)->plaintext; $item['title'] = $element->find('a.detLink', 0)->plaintext; $item['magnet'] = $element->find('a', 3)->href; @@ -174,4 +120,58 @@ class ThePirateBayBridge extends BridgeAbstract { } } } + + private function parseDateTimestamp($element){ + $guessedDate = $element->find('font', 0)->plaintext; + $guessedDate = explode('Uploaded ', $guessedDate)[1]; + $guessedDate = explode(',', $guessedDate)[0]; + + if(count(explode(':', $guessedDate)) == 1) { + $guessedDate = strptime($guessedDate, '%m-%d %Y'); + $timestamp = mktime( + 0, + 0, + 0, + $guessedDate['tm_mon'] + 1, + $guessedDate['tm_mday'], + 1900 + $guessedDate['tm_year'] + ); + } elseif(explode(' ', $guessedDate)[0] == 'Today') { + $guessedDate = strptime( + explode(' ', $guessedDate)[1], '%H:%M' + ); + + $timestamp = mktime( + $guessedDate['tm_hour'], + $guessedDate['tm_min'], + 0, + date('m'), + date('d'), + date('Y') + ); + } elseif(explode(' ', $guessedDate)[0] == 'Y-day') { + $guessedDate = strptime( + explode(' ', $guessedDate)[1], '%H:%M' + ); + + $timestamp = mktime( + $guessedDate['tm_hour'], + $guessedDate['tm_min'], + 0, + date('m', time() - 24 * 60 * 60), + date('d', time() - 24 * 60 * 60), + date('Y', time() - 24 * 60 * 60) + ); + } else { + $guessedDate = strptime($guessedDate, '%m-%d %H:%M'); + $timestamp = mktime( + $guessedDate['tm_hour'], + $guessedDate['tm_min'], + 0, + $guessedDate['tm_mon'] + 1, + $guessedDate['tm_mday'], + date('Y')); + } + return $timestamp; + } } diff --git a/bridges/TheWhiteboardBridge.php b/bridges/TheWhiteboardBridge.php new file mode 100644 index 0000000..051d15e --- /dev/null +++ b/bridges/TheWhiteboardBridge.php @@ -0,0 +1,22 @@ +<?php +class TheWhiteboardBridge extends BridgeAbstract { + const NAME = 'The Whiteboard'; + const URI = 'https://www.the-whiteboard.com/'; + const DESCRIPTION = 'Get the latest comic from The Whiteboard'; + const MAINTAINER = 'CyberJacob'; + + public function collectData() { + $item = array(); + + $html = getSimpleHTMLDOM(self::URI) or returnServerError('Could not load The Whiteboard.'); + + $image = $html->find('center', 1)->find('img', 0); + $image->src = self::URI . '/' . $image->src; + + $item['title'] = explode("\r\n", $html->find('center', 1)->plaintext)[0]; + $item['content'] = $image; + $item['timestamp'] = explode("\r\n", $html->find('center', 1)->plaintext)[0]; + + $this->items[] = $item; + } +} diff --git a/bridges/VarietyBridge.php b/bridges/VarietyBridge.php new file mode 100644 index 0000000..a2e6170 --- /dev/null +++ b/bridges/VarietyBridge.php @@ -0,0 +1,30 @@ +<?php +class VarietyBridge extends FeedExpander { + + const MAINTAINER = 'IceWreck'; + const NAME = 'Variety Bridge'; + const URI = 'https://variety.com'; + const CACHE_TIMEOUT = 3600; + const DESCRIPTION = 'RSS feed for Variety'; + + public function collectData(){ + $this->collectExpandableDatas('http://feeds.feedburner.com/variety/headlines', 15); + } + + protected function parseItem($newsItem){ + $item = parent::parseItem($newsItem); + // $articlePage gets the entire page's contents + $articlePage = getSimpleHTMLDOM($newsItem->link); + + // Remove Script tags + foreach($articlePage->find('script') as $script_tag) { + $script_tag->remove(); + } + $article = $articlePage->find('div.c-featured-media', 0); + $article = $article . $articlePage->find('.c-content', 0); + + $item['content'] = $article; + + return $item; + } +} diff --git a/bridges/ViceBridge.php b/bridges/ViceBridge.php new file mode 100644 index 0000000..4dccb8e --- /dev/null +++ b/bridges/ViceBridge.php @@ -0,0 +1,38 @@ +<?php +class ViceBridge extends FeedExpander { + const MAINTAINER = 'IceWreck'; + const NAME = 'Vice Bridge'; + const URI = 'https://www.vice.com/'; + const CACHE_TIMEOUT = 3600; // This is a news site, so don't cache for more than 10 mins + const DESCRIPTION = 'RSS feed for vice publications like Vice News, Munchies, Motherboard, etc.'; + const PARAMETERS = array( array( + 'feed' => array( + 'name' => 'Feed', + 'type' => 'list', + 'values' => array( + 'Vice News' => 'rss', + 'Motherboard - Tech' => 'en_us/rss/topic/tech', + 'Entertainment' => 'en_us/rss/topic/entertainment', + 'Noisey - Music' => 'en_us/rss/topic/music', + 'Munchies - Food' => 'en_us/rss/topic/food' + ) + ) + )); + + public function collectData(){ + $feed = $this->getInput('feed'); + $feedURL = 'https://www.vice.com/' . $feed; + $this->collectExpandableDatas($feedURL, 10); + } + + protected function parseItem($newsItem){ + $item = parent::parseItem($newsItem); + // $articlePage gets the entire page's contents + $articlePage = getSimpleHTMLDOM($newsItem->link); + // text and embedded content + $article = $article . $articlePage->find('.article__body', 0); + $item['content'] = $article; + + return $item; + } +} diff --git a/bridges/VieDeMerdeBridge.php b/bridges/VieDeMerdeBridge.php new file mode 100644 index 0000000..1224798 --- /dev/null +++ b/bridges/VieDeMerdeBridge.php @@ -0,0 +1,56 @@ +<?php +class VieDeMerdeBridge extends BridgeAbstract { + + const MAINTAINER = 'floviolleau'; + const NAME = 'VieDeMerde Bridge'; + const URI = 'https://viedemerde.fr'; + const DESCRIPTION = 'Returns latest quotes from VieDeMerde.'; + const CACHE_TIMEOUT = 7200; + + const PARAMETERS = array(array( + 'item_limit' => array( + 'name' => 'Limit number of returned items', + 'type' => 'number', + 'defaultValue' => 20 + ) + )); + + public function collectData() { + $limit = $this->getInput('item_limit'); + + if ($limit < 1) { + $limit = 20; + } + + $html = getSimpleHTMLDOM(self::URI, array()) + or returnServerError('Could not request VieDeMerde.'); + + $quotes = $html->find('article.article-panel'); + if(sizeof($quotes) === 0) { + return; + } + + foreach($quotes as $quote) { + $item = array(); + $item['uri'] = self::URI . $quote->find('.article-contents a', 0)->href; + $titleContent = $quote->find('.article-contents a h2.classic-title', 0); + + if($titleContent) { + $item['title'] = html_entity_decode($titleContent->plaintext, ENT_QUOTES); + } else { + continue; + } + + $quote->find('.article-contents a h2.classic-title', 0)->outertext = ''; + $item['content'] = $quote->find('.article-contents a', 0)->innertext; + $item['author'] = $quote->find('.article-topbar', 0)->innertext; + $item['uid'] = hash('sha256', $item['title']); + + $this->items[] = $item; + + if (count($this->items) >= $limit) { + break; + } + } + } +} diff --git a/bridges/VkBridge.php b/bridges/VkBridge.php index f9aaa66..713b86f 100644 --- a/bridges/VkBridge.php +++ b/bridges/VkBridge.php @@ -3,7 +3,9 @@ class VkBridge extends BridgeAbstract { - const MAINTAINER = 'ahiles3005'; + const MAINTAINER = 'em92'; + // const MAINTAINER = 'pmaziere'; + // const MAINTAINER = 'ahiles3005'; const NAME = 'VK.com'; const URI = 'https://vk.com/'; const CACHE_TIMEOUT = 300; // 5min @@ -26,7 +28,7 @@ class VkBridge extends BridgeAbstract protected function getAccessToken() { - return 'c8071613517c155c6cfbd2a059b2718e9c37b89094c4766834969dda75f657a2c1cbb49bab4c5e649f1db'; + return 'e69b2db9f6cd4a97c0716893232587165c18be85bc1af1834560125c1d3c8ec281eb407a78cca0ae16776'; } public function getURI() @@ -165,7 +167,7 @@ class VkBridge extends BridgeAbstract } // get all photos - foreach($post->find('div.wall_text > a.page_post_thumb_wrap') as $a) { + foreach($post->find('div.wall_text a.page_post_thumb_wrap') as $a) { $result = $this->getPhoto($a); if ($result == null) continue; $a->outertext = ''; @@ -237,6 +239,41 @@ class VkBridge extends BridgeAbstract $a->outertext = ''; } + // fix links and get post hashtags + $hashtags = array(); + foreach($post->find('a') as $a) { + $href = $a->getAttribute('href'); + $innertext = $a->innertext; + + $hashtag_prefix = '/feed?section=search&q=%23'; + $hashtag = null; + + if ($href && substr($href, 0, strlen($hashtag_prefix)) === $hashtag_prefix) { + $hashtag = urldecode(substr($href, strlen($hashtag_prefix))); + } else if (substr($innertext, 0, 1) == '#') { + $hashtag = $innertext; + } + + if ($hashtag) { + $a->outertext = $innertext; + $hashtags[] = $hashtag; + continue; + } + + $parsed_url = parse_url($href); + + if (array_key_exists('path', $parsed_url) === false) continue; + + if (strpos($parsed_url['path'], '/away.php') === 0) { + parse_str($parsed_url['query'], $parsed_query); + $a->setAttribute('href', iconv( + 'windows-1251', + 'utf-8//ignore', + $parsed_query['to'] + )); + } + } + if (is_object($post->find('div.copy_quote', 0))) { if ($this->getInput('hide_reposts') === true) { continue; @@ -250,21 +287,9 @@ class VkBridge extends BridgeAbstract } $item = array(); - $item['content'] = strip_tags(backgroundToImg($post->find('div.wall_text', 0)->innertext), '<br><img>'); + $item['content'] = strip_tags(backgroundToImg($post->find('div.wall_text', 0)->innertext), '<a><br><img>'); $item['content'] .= $content_suffix; - $item['categories'] = array(); - - // get post hashtags - foreach($post->find('a') as $a) { - $href = $a->getAttribute('href'); - $prefix = '/feed?section=search&q=%23'; - $innertext = $a->innertext; - if ($href && substr($href, 0, strlen($prefix)) === $prefix) { - $item['categories'][] = urldecode(substr($href, strlen($prefix))); - } else if (substr($innertext, 0, 1) == '#') { - $item['categories'][] = $innertext; - } - } + $item['categories'] = $hashtags; // get post link $post_link = $post->find('a.post_link', 0)->getAttribute('href'); @@ -354,6 +379,8 @@ class VkBridge extends BridgeAbstract } $date = date_parse($strdate); + } elseif ($date['hour'] === false) { + $date['hour'] = $date['minute'] = '00'; } return strtotime($date['day'] . '-' . $date['month'] . '-' . $date['year'] . ' ' . $date['hour'] . ':' . $date['minute']); diff --git a/bridges/XbooruBridge.php b/bridges/XbooruBridge.php index d3605be..2b0f2e3 100644 --- a/bridges/XbooruBridge.php +++ b/bridges/XbooruBridge.php @@ -5,7 +5,7 @@ class XbooruBridge extends GelbooruBridge { const MAINTAINER = 'mitsukarenai'; const NAME = 'Xbooru'; - const URI = 'http://xbooru.com/'; + const URI = 'https://xbooru.com/'; const DESCRIPTION = 'Returns images from given page'; const PIDBYPAGE = 50; diff --git a/bridges/XenForoBridge.php b/bridges/XenForoBridge.php index 983654e..7e210ee 100644 --- a/bridges/XenForoBridge.php +++ b/bridges/XenForoBridge.php @@ -395,7 +395,7 @@ class XenForoBridge extends BridgeAbstract { */ private function fixDate($date, $lang = 'en-US') { - $mnamesen = [ + $mnamesen = array( 'January', 'Feburary', 'March', @@ -408,7 +408,7 @@ class XenForoBridge extends BridgeAbstract { 'October', 'November', 'December' - ]; + ); switch($lang) { case 'en-US': // example: Jun 9, 2018 at 11:46 PM @@ -418,7 +418,7 @@ class XenForoBridge extends BridgeAbstract { case 'de-DE': // example: 19 Juli 2018 um 19:27 Uhr - $mnamesde = [ + $mnamesde = array( 'Januar', 'Februar', 'März', @@ -431,9 +431,9 @@ class XenForoBridge extends BridgeAbstract { 'Oktober', 'November', 'Dezember' - ]; + ); - $mnamesdeshort = [ + $mnamesdeshort = array( 'Jan.', 'Feb.', 'Mär.', @@ -446,7 +446,7 @@ class XenForoBridge extends BridgeAbstract { 'Okt.', 'Nov.', 'Dez.' - ]; + ); $date = str_ireplace($mnamesde, $mnamesen, $date); $date = str_ireplace($mnamesdeshort, $mnamesen, $date); diff --git a/bridges/YahtzeeDevDiaryBridge.php b/bridges/YahtzeeDevDiaryBridge.php new file mode 100644 index 0000000..3e3b2b0 --- /dev/null +++ b/bridges/YahtzeeDevDiaryBridge.php @@ -0,0 +1,21 @@ +<?php +class YahtzeeDevDiaryBridge extends BridgeAbstract { + const MAINTAINER = 'somini'; + const NAME = "Yahtzee's Dev Diary"; + const URI = 'https://www.escapistmagazine.com/v2/yahtzees-dev-diary-completed-games-list/'; + const DESCRIPTION = 'Yahtzee’s Dev Diary Series'; + + public function collectData(){ + $html = getSimpleHTMLDOM($this->getURI()) + or returnServerError('Could not load content'); + + foreach($html->find('blockquote.wp-embedded-content a') as $element) { + $item = array(); + + $item['title'] = $element->innertext; + $item['uri'] = $element->href; + + $this->items[] = $item; + } + } +} diff --git a/bridges/ZoneTelechargementBridge.php b/bridges/ZoneTelechargementBridge.php index 44cdfce..ab7b947 100644 --- a/bridges/ZoneTelechargementBridge.php +++ b/bridges/ZoneTelechargementBridge.php @@ -7,9 +7,9 @@ class ZoneTelechargementBridge extends BridgeAbstract { * name of the bridge. This permits to keep the same RSS Feed URL. */ - const NAME = 'Annuaire Telechargement'; - const URI = 'https://www.annuaire-telechargement.com/'; - const DESCRIPTION = 'Suivi de série sur Annuaire Telechargement'; + const NAME = 'Zone Telechargement'; + const URI = 'https://www.zone-telechargement.net/'; + const DESCRIPTION = 'Suivi de série sur Zone Telechargement'; const MAINTAINER = 'sysadminstory'; const PARAMETERS = array( 'Suivre la publication des épisodes d\'une série en cours de diffusion' => array( @@ -17,14 +17,14 @@ class ZoneTelechargementBridge extends BridgeAbstract { 'name' => 'URL de la série', 'type' => 'text', 'required' => true, - 'title' => 'URL d\'une série sans le https://www.annuaire-telechargement.com/', + 'title' => 'URL d\'une série sans le https://wwv.zone-telechargement.net/', 'exampleValue' => 'telecharger-series/31079-halt-and-catch-fire-saison-4-french-hd720p.html' ) ) ); public function getIcon() { - return 'https://www.annuaire-telechargement.com/templates/Default/images/favicon.ico'; + return self::URI . '/templates/Default/images/favicon.ico'; } public function collectData(){ diff --git a/composer.json b/composer.json index 8748cb3..3c03eeb 100644 --- a/composer.json +++ b/composer.json @@ -1,12 +1,39 @@ { + "name": "rss-bridge/rss-bridge", + "description": "RSS-Bridge is a PHP project capable of generating RSS and Atom feeds for websites that don't have one. It can be used on webservers or as a stand-alone application in CLI mode.", + "keywords": [ + "php", + "rss", + "bridge", + "rss-bridge", + "atom", + "html", + "json", + "feed", + "cli" + ], + "homepage": "https://github.com/rss-bridge/rss-bridge/", + "license": "UNLICENSE", + "support": { + "issues": "https://github.com/rss-bridge/rss-bridge/issues/", + "wiki": "https://github.com/rss-bridge/rss-bridge/wiki/", + "source": "https://github.com/rss-bridge/rss-bridge/", + "rss": "https://github.com/RSS-Bridge/rss-bridge/commits/master.atom" + }, "require": { - "php": ">=5.6", - "ext-mbstring": "*", - "ext-sqlite3": "*", - "ext-curl": "*", - "ext-openssl": "*", - "ext-libxml": "*", - "ext-simplexml": "*", - "ext-json": "*" + "php": ">=5.6", + "ext-mbstring": "*", + "ext-curl": "*", + "ext-openssl": "*", + "ext-libxml": "*", + "ext-simplexml": "*", + "ext-json": "*" + }, + "require-dev": { + "phpunit/phpunit": "^6 || ^7" + }, + "suggest": { + "ext-memcached": "Allows to use memcached as cache type", + "ext-sqlite3": "Allows to use an SQLite database for caching" } } diff --git a/composer.lock b/composer.lock index 3d8d9f2..918c430 100644 --- a/composer.lock +++ b/composer.lock @@ -4,9 +4,1479 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "ef341ee18f28c7bd5832e188fe157734", + "content-hash": "b60dc7dd86ffc8be27b94fc71894cad0", "packages": [], - "packages-dev": [], + "packages-dev": [ + { + "name": "doctrine/instantiator", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/instantiator.git", + "reference": "a2c590166b2133a4633738648b6b064edae0814a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/a2c590166b2133a4633738648b6b064edae0814a", + "reference": "a2c590166b2133a4633738648b6b064edae0814a", + "shasum": "" + }, + "require": { + "php": "^7.1" + }, + "require-dev": { + "doctrine/coding-standard": "^6.0", + "ext-pdo": "*", + "ext-phar": "*", + "phpbench/phpbench": "^0.13", + "phpstan/phpstan-phpunit": "^0.11", + "phpstan/phpstan-shim": "^0.11", + "phpunit/phpunit": "^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "http://ocramius.github.com/" + } + ], + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://www.doctrine-project.org/projects/instantiator.html", + "keywords": [ + "constructor", + "instantiate" + ], + "time": "2019-03-17T17:37:11+00:00" + }, + { + "name": "myclabs/deep-copy", + "version": "1.9.3", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "007c053ae6f31bba39dfa19a7726f56e9763bbea" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/007c053ae6f31bba39dfa19a7726f56e9763bbea", + "reference": "007c053ae6f31bba39dfa19a7726f56e9763bbea", + "shasum": "" + }, + "require": { + "php": "^7.1" + }, + "replace": { + "myclabs/deep-copy": "self.version" + }, + "require-dev": { + "doctrine/collections": "^1.0", + "doctrine/common": "^2.6", + "phpunit/phpunit": "^7.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + }, + "files": [ + "src/DeepCopy/deep_copy.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "time": "2019-08-09T12:45:53+00:00" + }, + { + "name": "phar-io/manifest", + "version": "1.0.3", + "source": { + "type": "git", + "url": "https://github.com/phar-io/manifest.git", + "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", + "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-phar": "*", + "phar-io/version": "^2.0", + "php": "^5.6 || ^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "time": "2018-07-08T19:23:20+00:00" + }, + { + "name": "phar-io/version", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/version.git", + "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/version/zipball/45a2ec53a73c70ce41d55cedef9063630abaf1b6", + "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Library for handling version information and constraints", + "time": "2018-07-08T19:19:57+00:00" + }, + { + "name": "phpdocumentor/reflection-common", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionCommon.git", + "reference": "63a995caa1ca9e5590304cd845c15ad6d482a62a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/63a995caa1ca9e5590304cd845c15ad6d482a62a", + "reference": "63a995caa1ca9e5590304cd845c15ad6d482a62a", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "require-dev": { + "phpunit/phpunit": "~6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jaap van Otterdijk", + "email": "opensource@ijaap.nl" + } + ], + "description": "Common reflection classes used by phpdocumentor to reflect the code structure", + "homepage": "http://www.phpdoc.org", + "keywords": [ + "FQSEN", + "phpDocumentor", + "phpdoc", + "reflection", + "static analysis" + ], + "time": "2018-08-07T13:53:10+00:00" + }, + { + "name": "phpdocumentor/reflection-docblock", + "version": "4.3.2", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "b83ff7cfcfee7827e1e78b637a5904fe6a96698e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/b83ff7cfcfee7827e1e78b637a5904fe6a96698e", + "reference": "b83ff7cfcfee7827e1e78b637a5904fe6a96698e", + "shasum": "" + }, + "require": { + "php": "^7.0", + "phpdocumentor/reflection-common": "^1.0.0 || ^2.0.0", + "phpdocumentor/type-resolver": "~0.4 || ^1.0.0", + "webmozart/assert": "^1.0" + }, + "require-dev": { + "doctrine/instantiator": "^1.0.5", + "mockery/mockery": "^1.0", + "phpunit/phpunit": "^6.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", + "time": "2019-09-12T14:27:41+00:00" + }, + { + "name": "phpdocumentor/type-resolver", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/TypeResolver.git", + "reference": "2e32a6d48972b2c1976ed5d8967145b6cec4a4a9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/2e32a6d48972b2c1976ed5d8967145b6cec4a4a9", + "reference": "2e32a6d48972b2c1976ed5d8967145b6cec4a4a9", + "shasum": "" + }, + "require": { + "php": "^7.1", + "phpdocumentor/reflection-common": "^2.0" + }, + "require-dev": { + "ext-tokenizer": "^7.1", + "mockery/mockery": "~1", + "phpunit/phpunit": "^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", + "time": "2019-08-22T18:11:29+00:00" + }, + { + "name": "phpspec/prophecy", + "version": "1.9.0", + "source": { + "type": "git", + "url": "https://github.com/phpspec/prophecy.git", + "reference": "f6811d96d97bdf400077a0cc100ae56aa32b9203" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/f6811d96d97bdf400077a0cc100ae56aa32b9203", + "reference": "f6811d96d97bdf400077a0cc100ae56aa32b9203", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.0.2", + "php": "^5.3|^7.0", + "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0|^5.0", + "sebastian/comparator": "^1.1|^2.0|^3.0", + "sebastian/recursion-context": "^1.0|^2.0|^3.0" + }, + "require-dev": { + "phpspec/phpspec": "^2.5|^3.2", + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.8.x-dev" + } + }, + "autoload": { + "psr-4": { + "Prophecy\\": "src/Prophecy" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + }, + { + "name": "Marcello Duarte", + "email": "marcello.duarte@gmail.com" + } + ], + "description": "Highly opinionated mocking framework for PHP 5.3+", + "homepage": "https://github.com/phpspec/prophecy", + "keywords": [ + "Double", + "Dummy", + "fake", + "mock", + "spy", + "stub" + ], + "time": "2019-10-03T11:07:50+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "6.1.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "807e6013b00af69b6c5d9ceb4282d0393dbb9d8d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/807e6013b00af69b6c5d9ceb4282d0393dbb9d8d", + "reference": "807e6013b00af69b6c5d9ceb4282d0393dbb9d8d", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-xmlwriter": "*", + "php": "^7.1", + "phpunit/php-file-iterator": "^2.0", + "phpunit/php-text-template": "^1.2.1", + "phpunit/php-token-stream": "^3.0", + "sebastian/code-unit-reverse-lookup": "^1.0.1", + "sebastian/environment": "^3.1 || ^4.0", + "sebastian/version": "^2.0.1", + "theseer/tokenizer": "^1.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.0" + }, + "suggest": { + "ext-xdebug": "^2.6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "time": "2018-10-31T16:06:48+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "050bedf145a257b1ff02746c31894800e5122946" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/050bedf145a257b1ff02746c31894800e5122946", + "reference": "050bedf145a257b1ff02746c31894800e5122946", + "shasum": "" + }, + "require": { + "php": "^7.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "time": "2018-09-13T20:33:42+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "time": "2015-06-21T13:50:34+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "2.1.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "1038454804406b0b5f5f520358e78c1c2f71501e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/1038454804406b0b5f5f520358e78c1c2f71501e", + "reference": "1038454804406b0b5f5f520358e78c1c2f71501e", + "shasum": "" + }, + "require": { + "php": "^7.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "time": "2019-06-07T04:22:29+00:00" + }, + { + "name": "phpunit/php-token-stream", + "version": "3.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-token-stream.git", + "reference": "995192df77f63a59e47f025390d2d1fdf8f425ff" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/995192df77f63a59e47f025390d2d1fdf8f425ff", + "reference": "995192df77f63a59e47f025390d2d1fdf8f425ff", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": "^7.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Wrapper around PHP's tokenizer extension.", + "homepage": "https://github.com/sebastianbergmann/php-token-stream/", + "keywords": [ + "tokenizer" + ], + "time": "2019-09-17T06:23:10+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "7.5.17", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "4c92a15296e58191a4cd74cff3b34fc8e374174a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/4c92a15296e58191a4cd74cff3b34fc8e374174a", + "reference": "4c92a15296e58191a4cd74cff3b34fc8e374174a", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.1", + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "myclabs/deep-copy": "^1.7", + "phar-io/manifest": "^1.0.2", + "phar-io/version": "^2.0", + "php": "^7.1", + "phpspec/prophecy": "^1.7", + "phpunit/php-code-coverage": "^6.0.7", + "phpunit/php-file-iterator": "^2.0.1", + "phpunit/php-text-template": "^1.2.1", + "phpunit/php-timer": "^2.1", + "sebastian/comparator": "^3.0", + "sebastian/diff": "^3.0", + "sebastian/environment": "^4.0", + "sebastian/exporter": "^3.1", + "sebastian/global-state": "^2.0", + "sebastian/object-enumerator": "^3.0.3", + "sebastian/resource-operations": "^2.0", + "sebastian/version": "^2.0.1" + }, + "conflict": { + "phpunit/phpunit-mock-objects": "*" + }, + "require-dev": { + "ext-pdo": "*" + }, + "suggest": { + "ext-soap": "*", + "ext-xdebug": "*", + "phpunit/php-invoker": "^2.0" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "7.5-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "time": "2019-10-28T10:37:36+00:00" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", + "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.7 || ^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Looks up which function or method a line of code belongs to", + "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "time": "2017-03-04T06:30:41+00:00" + }, + { + "name": "sebastian/comparator", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "5de4fc177adf9bce8df98d8d141a7559d7ccf6da" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/5de4fc177adf9bce8df98d8d141a7559d7ccf6da", + "reference": "5de4fc177adf9bce8df98d8d141a7559d7ccf6da", + "shasum": "" + }, + "require": { + "php": "^7.1", + "sebastian/diff": "^3.0", + "sebastian/exporter": "^3.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "https://github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "time": "2018-07-12T15:12:46+00:00" + }, + { + "name": "sebastian/diff", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "720fcc7e9b5cf384ea68d9d930d480907a0c1a29" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/720fcc7e9b5cf384ea68d9d930d480907a0c1a29", + "reference": "720fcc7e9b5cf384ea68d9d930d480907a0c1a29", + "shasum": "" + }, + "require": { + "php": "^7.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.5 || ^8.0", + "symfony/process": "^2 || ^3.3 || ^4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff", + "udiff", + "unidiff", + "unified diff" + ], + "time": "2019-02-04T06:01:07+00:00" + }, + { + "name": "sebastian/environment", + "version": "4.2.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "f2a2c8e1c97c11ace607a7a667d73d47c19fe404" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/f2a2c8e1c97c11ace607a7a667d73d47c19fe404", + "reference": "f2a2c8e1c97c11ace607a7a667d73d47c19fe404", + "shasum": "" + }, + "require": { + "php": "^7.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.5" + }, + "suggest": { + "ext-posix": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "time": "2019-05-05T09:05:15+00:00" + }, + { + "name": "sebastian/exporter", + "version": "3.1.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "68609e1261d215ea5b21b7987539cbfbe156ec3e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/68609e1261d215ea5b21b7987539cbfbe156ec3e", + "reference": "68609e1261d215ea5b21b7987539cbfbe156ec3e", + "shasum": "" + }, + "require": { + "php": "^7.0", + "sebastian/recursion-context": "^3.0" + }, + "require-dev": { + "ext-mbstring": "*", + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "http://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "time": "2019-09-14T09:02:43+00:00" + }, + { + "name": "sebastian/global-state", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", + "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", + "shasum": "" + }, + "require": { + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "suggest": { + "ext-uopz": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "time": "2017-04-27T15:39:26+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/7cfd9e65d11ffb5af41198476395774d4c8a84c5", + "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5", + "shasum": "" + }, + "require": { + "php": "^7.0", + "sebastian/object-reflector": "^1.1.1", + "sebastian/recursion-context": "^3.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "time": "2017-08-03T12:35:26+00:00" + }, + { + "name": "sebastian/object-reflector", + "version": "1.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "773f97c67f28de00d397be301821b06708fca0be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/773f97c67f28de00d397be301821b06708fca0be", + "reference": "773f97c67f28de00d397be301821b06708fca0be", + "shasum": "" + }, + "require": { + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Allows reflection of object attributes, including inherited and non-public ones", + "homepage": "https://github.com/sebastianbergmann/object-reflector/", + "time": "2017-03-29T09:07:27+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8", + "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8", + "shasum": "" + }, + "require": { + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "http://www.github.com/sebastianbergmann/recursion-context", + "time": "2017-03-03T06:23:57+00:00" + }, + { + "name": "sebastian/resource-operations", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/resource-operations.git", + "reference": "4d7a795d35b889bf80a0cc04e08d77cedfa917a9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/4d7a795d35b889bf80a0cc04e08d77cedfa917a9", + "reference": "4d7a795d35b889bf80a0cc04e08d77cedfa917a9", + "shasum": "" + }, + "require": { + "php": "^7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides a list of PHP built-in functions that operate on resources", + "homepage": "https://www.github.com/sebastianbergmann/resource-operations", + "time": "2018-10-04T04:07:39+00:00" + }, + { + "name": "sebastian/version", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019", + "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "time": "2016-10-03T07:35:21+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.12.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "550ebaac289296ce228a706d0867afc34687e3f4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/550ebaac289296ce228a706d0867afc34687e3f4", + "reference": "550ebaac289296ce228a706d0867afc34687e3f4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.12-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "time": "2019-08-06T08:03:45+00:00" + }, + { + "name": "theseer/tokenizer", + "version": "1.1.3", + "source": { + "type": "git", + "url": "https://github.com/theseer/tokenizer.git", + "reference": "11336f6f84e16a720dae9d8e6ed5019efa85a0f9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/11336f6f84e16a720dae9d8e6ed5019efa85a0f9", + "reference": "11336f6f84e16a720dae9d8e6ed5019efa85a0f9", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": "^7.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + } + ], + "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", + "time": "2019-06-13T22:48:21+00:00" + }, + { + "name": "webmozart/assert", + "version": "1.5.0", + "source": { + "type": "git", + "url": "https://github.com/webmozart/assert.git", + "reference": "88e6d84706d09a236046d686bbea96f07b3a34f4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozart/assert/zipball/88e6d84706d09a236046d686bbea96f07b3a34f4", + "reference": "88e6d84706d09a236046d686bbea96f07b3a34f4", + "shasum": "" + }, + "require": { + "php": "^5.3.3 || ^7.0", + "symfony/polyfill-ctype": "^1.8" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.36 || ^7.5.13" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\Assert\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Assertions to validate method input/output with nice error messages.", + "keywords": [ + "assert", + "check", + "validate" + ], + "time": "2019-08-24T08:43:50+00:00" + } + ], "aliases": [], "minimum-stability": "stable", "stability-flags": [], @@ -15,7 +1485,6 @@ "platform": { "php": ">=5.6", "ext-mbstring": "*", - "ext-sqlite3": "*", "ext-curl": "*", "ext-openssl": "*", "ext-libxml": "*", diff --git a/config.default.ini.php b/config.default.ini.php index b7d4fba..7d0bdaa 100644 --- a/config.default.ini.php +++ b/config.default.ini.php @@ -61,6 +61,18 @@ username = "" ; Use a strong password to prevent others from guessing your login! password = "" +[error] + +; Defines how error messages are returned by RSS-Bridge +; +; "feed" = As part of the feed (default) +; "http" = As HTTP error message +; "none" = No errors are reported +output = "feed" + +; Defines how often an error must occur before it is reported to the user +report_limit = 1 + ; --- Cache specific configuration --------------------------------------------- [SQLiteCache] diff --git a/formats/AtomFormat.php b/formats/AtomFormat.php index 1159a61..a1ecfcf 100644 --- a/formats/AtomFormat.php +++ b/formats/AtomFormat.php @@ -7,6 +7,8 @@ * https://validator.w3.org/feed/ */ class AtomFormat extends FormatAbstract{ + const MIME_TYPE = 'application/atom+xml'; + const LIMIT_TITLE = 140; public function stringify(){ @@ -147,7 +149,7 @@ EOD; public function display(){ $this - ->setContentType('application/atom+xml; charset=' . $this->getCharset()) + ->setContentType(self::MIME_TYPE . '; charset=' . $this->getCharset()) ->callContentType(); return parent::display(); diff --git a/formats/HtmlFormat.php b/formats/HtmlFormat.php index ebb6b78..49d9ca6 100644 --- a/formats/HtmlFormat.php +++ b/formats/HtmlFormat.php @@ -1,5 +1,7 @@ <?php class HtmlFormat extends FormatAbstract { + const MIME_TYPE = 'text/html'; + public function stringify(){ $extraInfos = $this->getExtraInfos(); $title = htmlspecialchars($extraInfos['name']); @@ -10,6 +12,7 @@ class HtmlFormat extends FormatAbstract { $formatFac->setWorkingDir(PATH_LIB_FORMATS); $buttons = ''; + $links = ''; foreach($formatFac->getFormatNames() as $format) { if(strcasecmp($format, 'HTML') === 0) { @@ -18,6 +21,9 @@ class HtmlFormat extends FormatAbstract { $query = str_replace('format=Html', 'format=' . $format, htmlentities($_SERVER['QUERY_STRING'])); $buttons .= $this->buildButton($format, $query) . PHP_EOL; + + $mime = $formatFac->create($format)->getMimeType(); + $links .= $this->buildLink($format, $query, $mime) . PHP_EOL; } $entries = ''; @@ -99,6 +105,7 @@ EOD; <title>{$title}</title> <link href="static/HtmlFormat.css" rel="stylesheet"> <link rel="icon" type="image/png" href="static/favicon.png"> + {$links} <meta name="robots" content="noindex, follow"> </head> <body> @@ -120,7 +127,7 @@ EOD; public function display() { $this - ->setContentType('text/html; charset=' . $this->getCharset()) + ->setContentType(self::MIME_TYPE . '; charset=' . $this->getCharset()) ->callContentType(); return parent::display(); @@ -131,4 +138,11 @@ EOD; <a href="./?{$query}"><button class="rss-feed">{$format}</button></a> EOD; } + + private function buildLink($format, $query, $mime) { + return <<<EOD +<link href="./?{$query}" title="{$format}" rel="alternate" type="{$mime}"> + +EOD; + } } diff --git a/formats/JsonFormat.php b/formats/JsonFormat.php index 5d09162..2c5cd07 100644 --- a/formats/JsonFormat.php +++ b/formats/JsonFormat.php @@ -8,6 +8,8 @@ * https://github.com/vigetlabs/json-feed-validator */ class JsonFormat extends FormatAbstract { + const MIME_TYPE = 'application/json'; + const VENDOR_EXCLUDES = array( 'author', 'title', @@ -119,7 +121,7 @@ class JsonFormat extends FormatAbstract { public function display(){ $this - ->setContentType('application/json; charset=' . $this->getCharset()) + ->setContentType(self::MIME_TYPE . '; charset=' . $this->getCharset()) ->callContentType(); return parent::display(); diff --git a/formats/MrssFormat.php b/formats/MrssFormat.php index 836a361..8bf569a 100644 --- a/formats/MrssFormat.php +++ b/formats/MrssFormat.php @@ -25,6 +25,8 @@ * RSS 2.0 feed that works with feed readers that don't support the extension. */ class MrssFormat extends FormatAbstract { + const MIME_TYPE = 'application/rss+xml'; + const ALLOWED_IMAGE_EXT = array( '.gif', '.jpg', '.png' ); @@ -150,7 +152,7 @@ EOD; public function display(){ $this - ->setContentType('application/rss+xml; charset=' . $this->getCharset()) + ->setContentType(self::MIME_TYPE . '; charset=' . $this->getCharset()) ->callContentType(); return parent::display(); diff --git a/formats/PlaintextFormat.php b/formats/PlaintextFormat.php index 591a4b3..5a0522c 100644 --- a/formats/PlaintextFormat.php +++ b/formats/PlaintextFormat.php @@ -4,6 +4,8 @@ * Returns $this->items as raw php data. */ class PlaintextFormat extends FormatAbstract { + const MIME_TYPE = 'text/plain'; + public function stringify(){ $items = $this->getItems(); $data = array(); @@ -22,7 +24,7 @@ class PlaintextFormat extends FormatAbstract { public function display(){ $this - ->setContentType('text/plain; charset=' . $this->getCharset()) + ->setContentType(self::MIME_TYPE . '; charset=' . $this->getCharset()) ->callContentType(); return parent::display(); diff --git a/lib/BridgeAbstract.php b/lib/BridgeAbstract.php index b4eb9ff..c8ad79c 100644 --- a/lib/BridgeAbstract.php +++ b/lib/BridgeAbstract.php @@ -165,8 +165,8 @@ abstract class BridgeAbstract implements BridgeInterface { foreach(static::PARAMETERS['global'] as $name => $properties) { if(isset($inputs[$name])) { $value = $inputs[$name]; - } elseif(isset($properties['value'])) { - $value = $properties['value']; + } elseif(isset($properties['defaultValue'])) { + $value = $properties['defaultValue']; } else { continue; } diff --git a/lib/BridgeCard.php b/lib/BridgeCard.php index c6f3822..4353f64 100644 --- a/lib/BridgeCard.php +++ b/lib/BridgeCard.php @@ -122,6 +122,11 @@ This bridge is not fetching its content through a secure connection</div>'; } elseif($inputEntry['type'] === 'checkbox') { $form .= self::getCheckboxInput($inputEntry, $idArg, $id); } + + if(isset($inputEntry['title'])) + $form .= '<i class="info" title="' . filter_var($inputEntry['title'], FILTER_SANITIZE_STRING) . '">i</i>'; + else + $form .= '<i></i>'; } $form .= '</div>'; @@ -152,9 +157,6 @@ This bridge is not fetching its content through a secure connection</div>'; if(isset($entry['pattern'])) $retVal .= ' pattern="' . $entry['pattern'] . '"'; - if(isset($entry['title'])) - $retVal .= ' title="' . filter_var($entry['title'], FILTER_SANITIZE_STRING) . '"'; - return $retVal; } diff --git a/lib/Configuration.php b/lib/Configuration.php index fc575d6..6d52423 100644 --- a/lib/Configuration.php +++ b/lib/Configuration.php @@ -28,7 +28,7 @@ final class Configuration { * * @todo Replace this property by a constant. */ - public static $VERSION = '2019-09-12'; + public static $VERSION = '2019-12-01'; /** * Holds the configuration data. @@ -201,6 +201,13 @@ final class Configuration { && !filter_var(self::getConfig('admin', 'email'), FILTER_VALIDATE_EMAIL)) self::reportConfigurationError('admin', 'email', 'Is not a valid email address'); + if(!is_string(self::getConfig('error', 'output'))) + self::reportConfigurationError('error', 'output', 'Is not a valid String'); + + if(!is_numeric(self::getConfig('error', 'report_limit')) + || self::getConfig('error', 'report_limit') < 1) + self::reportConfigurationError('admin', 'report_limit', 'Value is invalid'); + } /** diff --git a/lib/FormatAbstract.php b/lib/FormatAbstract.php index 5395d56..5c4b87f 100644 --- a/lib/FormatAbstract.php +++ b/lib/FormatAbstract.php @@ -21,6 +21,9 @@ abstract class FormatAbstract implements FormatInterface { /** The default charset (UTF-8) */ const DEFAULT_CHARSET = 'UTF-8'; + /** MIME type of format output */ + const MIME_TYPE = 'text/plain'; + /** @var string|null $contentType The content type */ protected $contentType = null; @@ -39,6 +42,11 @@ abstract class FormatAbstract implements FormatInterface { /** @var array $extraInfos The extra infos */ protected $extraInfos; + /** {@inheritdoc} */ + public function getMimeType(){ + return static::MIME_TYPE; + } + /** * {@inheritdoc} * diff --git a/lib/FormatInterface.php b/lib/FormatInterface.php index 68b0bd5..82049d4 100644 --- a/lib/FormatInterface.php +++ b/lib/FormatInterface.php @@ -67,6 +67,13 @@ interface FormatInterface { public function getExtraInfos(); /** + * Return MIME type + * + * @return string The MIME type + */ + public function getMimeType(); + + /** * Set charset * * @param string $charset The charset diff --git a/lib/ParameterValidator.php b/lib/ParameterValidator.php index f740888..149e8a4 100644 --- a/lib/ParameterValidator.php +++ b/lib/ParameterValidator.php @@ -191,6 +191,13 @@ class ParameterValidator { foreach($parameters as $context => $set) { $queriedContexts[$context] = null; + // Ensure all user data exist in the current context + $notInContext = array_diff_key($data, $set); + if(array_key_exists('global', $parameters)) + $notInContext = array_diff_key($notInContext, $parameters['global']); + if(sizeof($notInContext) > 0) + continue; + // Check if all parameters of the context are satisfied foreach($set as $id => $properties) { if(isset($data[$id]) && !empty($data[$id])) { diff --git a/lib/contents.php b/lib/contents.php index 8649c0b..b1e3128 100644 --- a/lib/contents.php +++ b/lib/contents.php @@ -37,11 +37,13 @@ * @param array $opts (optional) A list of cURL options as associative array in * the format `$opts[$option] = $value;`, where `$option` is any `CURLOPT_XXX` * option and `$value` the corresponding value. + * @param bool $returnHeader Returns an array of two elements 'header' and + * 'content' if enabled. * * For more information see http://php.net/manual/en/function.curl-setopt.php * @return string The contents. */ -function getContents($url, $header = array(), $opts = array()){ +function getContents($url, $header = array(), $opts = array(), $returnHeader = false){ Debug::log('Reading contents from "' . $url . '"'); // Initialize cache @@ -51,9 +53,14 @@ function getContents($url, $header = array(), $opts = array()){ $cache->setScope('server'); $cache->purgeCache(86400); // 24 hours (forced) - $params = [$url]; + $params = array($url); $cache->setKey($params); + $retVal = array( + 'header' => '', + 'content' => '', + ); + // Use file_get_contents if in CLI mode with no root certificates defined if(php_sapi_name() === 'cli' && empty(ini_get('curl.cainfo'))) { @@ -141,6 +148,7 @@ function getContents($url, $header = array(), $opts = array()){ $headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE); $header = substr($data, 0, $headerSize); + $retVal['header'] = $header; Debug::log('Response header: ' . $header); @@ -164,15 +172,18 @@ function getContents($url, $header = array(), $opts = array()){ if(in_array('no-cache', $directives) || in_array('no-store', $directives)) { // Skip caching Debug::log('Skip server side caching'); - return $data; + $retVal['content'] = $data; + break; } } Debug::log('Store response to cache'); $cache->saveData($data); - return $data; + $retVal['content'] = $data; + break; case 304: // Not modified, use cached data Debug::log('Contents not modified on host, returning cached data'); - return $cache->loadData(); + $retVal['content'] = $cache->loadData(); + break; default: if(array_key_exists('Server', $finalHeader) && strpos($finalHeader['Server'], 'cloudflare') !== false) { returnServerError(<<< EOD @@ -193,6 +204,8 @@ PHP error: $lastError EOD , $errorCode); } + + return ($returnHeader === true) ? $retVal : $retVal['content']; } /** @@ -291,7 +304,7 @@ function getSimpleHTMLDOMCached($url, $cache->setScope('pages'); $cache->purgeCache(86400); // 24 hours (forced) - $params = [$url]; + $params = array($url); $cache->setKey($params); // Determine if cached file is within duration diff --git a/lib/error.php b/lib/error.php index 9a0756f..4b7110f 100644 --- a/lib/error.php +++ b/lib/error.php @@ -41,3 +41,37 @@ function returnClientError($message){ function returnServerError($message){ returnError($message, 500); } + +/** + * Stores bridge-specific errors in a cache file. + * + * @param string $bridgeName The name of the bridge that failed. + * @param int $code The error code + * + * @return int The total number the same error has appeared + */ +function logBridgeError($bridgeName, $code) { + $cacheFac = new CacheFactory(); + $cacheFac->setWorkingDir(PATH_LIB_CACHES); + + $cache = $cacheFac->create(Configuration::getConfig('cache', 'type')); + $cache->setScope('error_reporting'); + $cache->setkey($bridgeName . '_' . $code); + $cache->purgeCache(86400); // 24 hours + + if($report = $cache->loadData()) { + $report = json_decode($report, true); + $report['time'] = time(); + $report['count']++; + } else { + $report = array( + 'error' => $code, + 'time' => time(), + 'count' => 1, + ); + } + + $cache->saveData(json_encode($report)); + + return $report['count']; +} diff --git a/static/connectivity.css b/static/connectivity.css new file mode 100644 index 0000000..5f891d2 --- /dev/null +++ b/static/connectivity.css @@ -0,0 +1,8 @@ +input:focus::-webkit-input-placeholder { opacity: 0; } +input:focus::-moz-placeholder { opacity: 0; } +input:focus::placeholder { opacity: 0; } +input:focus:-moz-placeholder { opacity: 0; } +input:focus:-ms-input-placeholder { opacity: 0; } + +.progress { height: 2px; } +.progressbar { width: 0%; }
\ No newline at end of file diff --git a/static/connectivity.js b/static/connectivity.js new file mode 100644 index 0000000..89f01f0 --- /dev/null +++ b/static/connectivity.js @@ -0,0 +1,256 @@ +var remote = location.href.substring(0, location.href.lastIndexOf("/")); +var bridges = []; +var abort = false; + +window.onload = function() { + + fetch(remote + '/index.php?action=list').then(function(response) { + return response.text() + }).then(function(data){ + processBridgeList(data); + }).catch(console.log.bind(console) + ); + +} + +function processBridgeList(data) { + + var list = JSON.parse(data); + + buildTable(list); + buildBridgeQueue(list); + checkNextBridgeAsync(); + +} + +function buildTable(bridgeList) { + + var table = document.createElement('table'); + table.classList.add('table'); + + var thead = document.createElement('thead'); + thead.innerHTML = ` + <tr> + <th scope="col">Bridge</th> + <th scope="col">Result</th> + </tr>`; + + var tbody = document.createElement('tbody'); + + for (var bridge in bridgeList.bridges) { + + var tr = document.createElement('tr'); + tr.classList.add('bg-secondary'); + tr.id = bridge; + + var td_bridge = document.createElement('td'); + td_bridge.innerText = bridgeList.bridges[bridge].name; + + // Link to the actual bridge on index.php + var a = document.createElement('a'); + a.href = remote + "/index.php?show_inactive=1#bridge-" + bridge; + a.target = '_blank'; + a.innerText = '[Show]'; + a.style.marginLeft = '5px'; + a.style.color = 'black'; + + td_bridge.appendChild(a); + tr.appendChild(td_bridge); + + var td_result = document.createElement('td'); + + if (bridgeList.bridges[bridge].status === 'active') { + td_result.innerHTML = '<i title="Scheduled" class="fas fa-hourglass-start"></i>'; + } else { + td_result.innerHTML = '<i title="Inactive" class="fas fa-times-circle"></i>'; + } + + tr.appendChild(td_result); + tbody.appendChild(tr); + + } + + table.appendChild(thead); + table.appendChild(tbody); + + var content = document.getElementById('main-content'); + content.appendChild(table); + +} + +function buildBridgeQueue(bridgeList) { + for (var bridge in bridgeList.bridges) { + if (bridgeList.bridges[bridge].status !== 'active') + continue; + bridges.push(bridge); + } +} + + +function checkNextBridgeAsync() { + return new Promise((resolve) => { + var msg = document.getElementById('status-message'); + var icon = document.getElementById('status-icon'); + + if (bridges.length === 0) { + msg.classList.remove('alert-primary'); + msg.classList.add('alert-success'); + msg.getElementsByTagName('span')[0].textContent = 'Done'; + + icon.classList.remove('fa-sync'); + icon.classList.add('fa-check'); + } else { + var bridge = bridges.shift(); + + msg.getElementsByTagName('span')[0].textContent = 'Processing ' + bridge + '...'; + + fetch(remote + '/index.php?action=Connectivity&bridge=' + bridge) + .then(function(response) { return response.text() }) + .then(JSON.parse) + .then(processBridgeResultAsync) + .then(markBridgeSuccessful, markBridgeFailed) + .then(checkAbortAsync) + .then(checkNextBridgeAsync, abortChecks) + .catch(console.log.bind(console)); + + search(); // Dynamically update search results + updateProgressBar(); + + } + + resolve(); + }); +} + +function abortChecks() { + return new Promise((resolve) => { + var msg = document.getElementById('status-message'); + + msg.classList.remove('alert-primary'); + msg.classList.add('alert-warning'); + msg.getElementsByTagName('span')[0].textContent = 'Aborted'; + + var icon = document.getElementById('status-icon'); + icon.classList.remove('fa-sync'); + icon.classList.add('fa-ban'); + + bridges.forEach((bridge) => { + markBridgeAborted(bridge); + }) + + resolve(); + }); +} + +function processBridgeResultAsync(result) { + return new Promise((resolve, reject) => { + if (result.successful) { + resolve(result); + } else { + reject(result); + } + }); +} + +function markBridgeSuccessful(result) { + return new Promise((resolve) => { + var tr = document.getElementById(result.bridge); + tr.classList.remove('bg-secondary'); + if (result.http_code == 200) { + tr.classList.add('bg-success'); + tr.children[1].innerHTML = '<i title="Successful" class="fas fa-check"></i>'; + } else { + tr.classList.add('bg-primary'); + tr.children[1].innerHTML = '<i title="Redirected" class="fas fa-directions"></i>'; + } + + resolve(); + }); +} + +function markBridgeFailed(result) { + return new Promise((resolve) => { + var tr = document.getElementById(result.bridge); + tr.classList.remove('bg-secondary'); + tr.classList.add('bg-danger'); + tr.children[1].innerHTML = '<i title="Failed" class="fas fa-exclamation-triangle"></i>'; + + resolve(); + }); +} + +function markBridgeAborted(bridge) { + return new Promise((resolve) => { + var tr = document.getElementById(bridge); + tr.classList.remove('bg-secondary'); + tr.classList.add('bg-warning'); + tr.children[1].innerHTML = '<i title="Aborted" class="fas fa-ban"></i>'; + + resolve(); + }); +} + +function checkAbortAsync() { + return new Promise((resolve, reject) => { + if (abort) { + reject(); + return; + } + + resolve(); + }); +} + +function updateProgressBar() { + + // This will break if the table changes + var total = document.getElementsByTagName('tr').length - 1; + var current = bridges.length; + var progress = (total - current) * 100 / total; + + var progressBar = document.getElementsByClassName('progress-bar')[0]; + + if(progressBar){ + progressBar.setAttribute('aria-valuenow', progress.toFixed(0)); + progressBar.style.width = progress.toFixed(0) + '%'; + } + +} + +function stopConnectivityChecks() { + abort = true; +} + +function search() { + + var input = document.getElementById('search'); + var filter = input.value.toUpperCase(); + var table = document.getElementsByTagName('table')[0]; + var tr = table.getElementsByTagName('tr'); + + for (var i = 0; i < tr.length; i++) { + + var td1 = tr[i].getElementsByTagName('td')[0]; + var td2 = tr[i].getElementsByTagName('td')[1]; + + if (td1) { + + var txtValue = td1.textContent || td1.innerText; + + var title = ''; + if(td2.getElementsByTagName('i')[0]) { + title = td2.getElementsByTagName('i')[0].title; + } + + if (txtValue.toUpperCase().indexOf(filter) > -1 + || title.toUpperCase().indexOf(filter) > -1) { + tr[i].style.display = ''; + } else { + tr[i].style.display = 'none'; + } + + } + + } + +}
\ No newline at end of file diff --git a/static/style.css b/static/style.css index 974aa78..5df2c51 100644 --- a/static/style.css +++ b/static/style.css @@ -184,12 +184,33 @@ form { content: ' :'; } +.info { + cursor: help; + opacity: 0.5; + width: 24px; + height: 24px; + font-size: 16px; + font-weight: bold; + font-style: italic; + line-height: 22px; + text-align: center; + color: #fff; + background-image: radial-gradient(#49afff, #1182DB); + -webkit-border-radius: 16px; + -moz-border-radius: 16px; + border-radius: 16px; +} + +.info:hover { + opacity: 1; +} + @supports (display: grid) { .parameters { display: grid; padding: 12px 0; - grid-template-columns: 40% max-content; + grid-template-columns: 40% max-content 24px; grid-column-gap: 10px; grid-row-gap: 5px; } @@ -339,6 +360,10 @@ h5 { margin: 3px auto 0; } + .info { + display: none; + } + @supports (display: grid) { .parameters { |