Compare commits
23 Commits
2025-01-26
...
master
Author | SHA1 | Date | |
---|---|---|---|
9922787aa9 | |||
![]() |
dee734d360 | ||
![]() |
744f996224 | ||
![]() |
f270cd35e7 | ||
![]() |
83c36a87e2 | ||
![]() |
810e17b556 | ||
![]() |
97f07cf216 | ||
![]() |
62fafdc24b | ||
![]() |
cd4cdcfd65 | ||
![]() |
00a24e2f69 | ||
![]() |
92b5e7093f | ||
![]() |
b52f01505d | ||
![]() |
e4c32bb046 | ||
![]() |
dd4dcfa59c | ||
![]() |
4e678c955f | ||
![]() |
549bed64d2 | ||
![]() |
94924d8e16 | ||
![]() |
920b21b1fd | ||
![]() |
935075072b | ||
![]() |
3ae7a10223 | ||
![]() |
bf431a6eae | ||
![]() |
824ac5e373 | ||
![]() |
ae8394d976 |
4
.github/ISSUE_TEMPLATE/bridge-request.md
vendored
4
.github/ISSUE_TEMPLATE/bridge-request.md
vendored
@ -49,9 +49,9 @@ Please describe what you expect from the bridge. Whenever possible provide sampl
|
|||||||
- _Default limit_: 5
|
- _Default limit_: 5
|
||||||
- [ ] Load full articles
|
- [ ] Load full articles
|
||||||
- _Cache articles_ (articles are stored in a local cache on first request): yes
|
- _Cache articles_ (articles are stored in a local cache on first request): yes
|
||||||
- _Cache timeout_ (max = 24 hours): 24 hours
|
- _Cache timeout_ : 24 hours
|
||||||
- [X] Balance requests (RSS-Bridge uses cached versions to reduce bandwith usage)
|
- [X] Balance requests (RSS-Bridge uses cached versions to reduce bandwith usage)
|
||||||
- _Timeout_ (default = 5 minutes, max = 24 hours): 5 minutes
|
- _Timeout_ (default = 5 minutes): 5 minutes
|
||||||
|
|
||||||
<!--Be aware that some options might not be available for your specific request due to technical limitations!-->
|
<!--Be aware that some options might not be available for your specific request due to technical limitations!-->
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
* [Binnette](https://github.com/Binnette)
|
* [Binnette](https://github.com/Binnette)
|
||||||
* [BoboTiG](https://github.com/BoboTiG)
|
* [BoboTiG](https://github.com/BoboTiG)
|
||||||
* [Bockiii](https://github.com/Bockiii)
|
* [Bockiii](https://github.com/Bockiii)
|
||||||
|
* [brtsos](https://github.com/brtsos)
|
||||||
* [captn3m0](https://github.com/captn3m0)
|
* [captn3m0](https://github.com/captn3m0)
|
||||||
* [chemel](https://github.com/chemel)
|
* [chemel](https://github.com/chemel)
|
||||||
* [Chouchen](https://github.com/Chouchen)
|
* [Chouchen](https://github.com/Chouchen)
|
||||||
|
@ -150,11 +150,11 @@ listen = /run/php/rss-bridge.sock
|
|||||||
listen.owner = www-data
|
listen.owner = www-data
|
||||||
listen.group = www-data
|
listen.group = www-data
|
||||||
|
|
||||||
# Create 10 workers standing by to serve requests
|
; Create 10 workers standing by to serve requests
|
||||||
pm = static
|
pm = static
|
||||||
pm.max_children = 10
|
pm.max_children = 10
|
||||||
|
|
||||||
# Respawn worker after 500 requests (workaround for memory leaks etc.)
|
; Respawn worker after 500 requests (workaround for memory leaks etc.)
|
||||||
pm.max_requests = 500
|
pm.max_requests = 500
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -460,7 +460,6 @@ See [CONTRIBUTORS.md](CONTRIBUTORS.md)
|
|||||||
|
|
||||||
RSS-Bridge uses caching to prevent services from banning your server for repeatedly updating feeds.
|
RSS-Bridge uses caching to prevent services from banning your server for repeatedly updating feeds.
|
||||||
The specific cache duration can be different between bridges.
|
The specific cache duration can be different between bridges.
|
||||||
Cached files are deleted automatically after 24 hours.
|
|
||||||
|
|
||||||
RSS-Bridge allows you to take full control over which bridges are displayed to the user.
|
RSS-Bridge allows you to take full control over which bridges are displayed to the user.
|
||||||
That way you can host your own RSS-Bridge service with your favorite collection of bridges!
|
That way you can host your own RSS-Bridge service with your favorite collection of bridges!
|
||||||
|
@ -67,7 +67,7 @@ class AnisearchBridge extends BridgeAbstract
|
|||||||
$trailerlink = $domarticle->find('section#trailers > div > div.swiper > ul.swiper-wrapper > li.swiper-slide > a', 0);
|
$trailerlink = $domarticle->find('section#trailers > div > div.swiper > ul.swiper-wrapper > li.swiper-slide > a', 0);
|
||||||
if (isset($trailerlink)) {
|
if (isset($trailerlink)) {
|
||||||
$trailersite = getSimpleHTMLDOM($baseurl . $trailerlink->href);
|
$trailersite = getSimpleHTMLDOM($baseurl . $trailerlink->href);
|
||||||
$trailer = $trailersite->find('div#player > iframe', 0);
|
$trailer = $trailersite->find('div#video > iframe', 0);
|
||||||
$trailer = $trailer->{'data-xsrc'};
|
$trailer = $trailer->{'data-xsrc'};
|
||||||
$ytlink = <<<EOT
|
$ytlink = <<<EOT
|
||||||
<br /><iframe width="560" height="315" src="$trailer" title="YouTube video player"
|
<br /><iframe width="560" height="315" src="$trailer" title="YouTube video player"
|
||||||
|
344
bridges/AuctionetBridge.php
Normal file
344
bridges/AuctionetBridge.php
Normal file
@ -0,0 +1,344 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class AuctionetBridge extends BridgeAbstract
|
||||||
|
{
|
||||||
|
const NAME = 'Auctionet';
|
||||||
|
const URI = 'https://www.auctionet.com';
|
||||||
|
const DESCRIPTION = 'Fetches info about auction objects from Auctionet (an auction platform for many European auction houses)';
|
||||||
|
const MAINTAINER = 'Qluxzz';
|
||||||
|
const PARAMETERS = [[
|
||||||
|
'category' => [
|
||||||
|
'name' => 'Category',
|
||||||
|
'type' => 'list',
|
||||||
|
'values' => [
|
||||||
|
'All categories' => '',
|
||||||
|
'Art' => [
|
||||||
|
'All' => '25-art',
|
||||||
|
'Drawings' => '119-drawings',
|
||||||
|
'Engravings & Prints' => '27-engravings-prints',
|
||||||
|
'Other' => '30-other',
|
||||||
|
'Paintings' => '28-paintings',
|
||||||
|
'Photography' => '26-photography',
|
||||||
|
'Sculptures & Bronzes' => '29-sculptures-bronzes',
|
||||||
|
],
|
||||||
|
'Asiatica' => [
|
||||||
|
'All' => '117-asiatica',
|
||||||
|
],
|
||||||
|
'Books, Maps & Manuscripts' => [
|
||||||
|
'All' => '50-books-maps-manuscripts',
|
||||||
|
'Autographs & Manuscripts' => '206-autographs-manuscripts',
|
||||||
|
'Books' => '204-books',
|
||||||
|
'Maps' => '205-maps',
|
||||||
|
'Other' => '207-other',
|
||||||
|
],
|
||||||
|
'Carpets & Textiles' => [
|
||||||
|
'All' => '35-carpets-textiles',
|
||||||
|
'Carpets' => '36-carpets',
|
||||||
|
'Textiles' => '37-textiles',
|
||||||
|
],
|
||||||
|
'Ceramics & Porcelain' => [
|
||||||
|
'All' => '9-ceramics-porcelain',
|
||||||
|
'European' => '10-european',
|
||||||
|
'Oriental' => '11-oriental',
|
||||||
|
'Rest of the world' => '12-rest-of-the-world',
|
||||||
|
'Tableware' => '210-tableware',
|
||||||
|
],
|
||||||
|
'Clocks & Watches' => [
|
||||||
|
'All' => '31-clocks-watches',
|
||||||
|
'Carriage & Miniature Clocks' => '258-carriage-miniature-clocks',
|
||||||
|
'Longcase clocks' => '32-longcase-clocks',
|
||||||
|
'Mantel clocks' => '33-mantel-clocks',
|
||||||
|
'Other clocks' => '34-other-clocks',
|
||||||
|
'Pocket & Stop Watches' => '110-pocket-stop-watches',
|
||||||
|
'Wall Clocks' => '127-wall-clocks',
|
||||||
|
'Wristwatches' => '15-wristwatches',
|
||||||
|
],
|
||||||
|
'Coins, Medals & Stamps' => [
|
||||||
|
'All' => '46-coins-medals-stamps',
|
||||||
|
'Coins' => '128-coins',
|
||||||
|
'Orders & Medals' => '135-orders-medals',
|
||||||
|
'Other' => '131-other',
|
||||||
|
'Stamps' => '136-stamps',
|
||||||
|
],
|
||||||
|
'Folk art' => [
|
||||||
|
'All' => '58-folk-art',
|
||||||
|
'Bowls & Boxes' => '121-bowls-boxes',
|
||||||
|
'Furniture' => '122-furniture',
|
||||||
|
'Other' => '123-other',
|
||||||
|
'Tools & Gears' => '120-tools-gears',
|
||||||
|
],
|
||||||
|
'Furniture' => [
|
||||||
|
'All' => '16-furniture',
|
||||||
|
'Armchairs & Chairs' => '18-armchairs-chairs',
|
||||||
|
'Chests of drawers' => '24-chests-of-drawers',
|
||||||
|
'Cupboards, Cabinets & Shelves' => '23-cupboards-cabinets-shelves',
|
||||||
|
'Dining room furniture' => '22-dining-room-furniture',
|
||||||
|
'Garden' => '21-garden',
|
||||||
|
'Other' => '17-other',
|
||||||
|
'Sofas & seatings' => '20-sofas-seatings',
|
||||||
|
'Tables' => '19-tables',
|
||||||
|
],
|
||||||
|
'Glass' => [
|
||||||
|
'All' => '6-glass',
|
||||||
|
'Art glass' => '208-art-glass',
|
||||||
|
'Other' => '8-other',
|
||||||
|
'Tableware' => '7-tableware',
|
||||||
|
'Utility glass' => '209-utility-glass',
|
||||||
|
],
|
||||||
|
'Jewellery & Gemstones' => [
|
||||||
|
'All' => '13-jewellery-gemstones',
|
||||||
|
'Alliance rings' => '113-alliance-rings',
|
||||||
|
'Bracelets' => '106-bracelets',
|
||||||
|
'Brooches & Pendants' => '107-brooches-pendants',
|
||||||
|
'Costume Jewellery' => '259-costume-jewellery',
|
||||||
|
'Cufflinks & Tie Pins' => '111-cufflinks-tie-pins',
|
||||||
|
'Ear studs' => '116-ear-studs',
|
||||||
|
'Earrings' => '115-earrings',
|
||||||
|
'Gemstones' => '48-gemstones',
|
||||||
|
'Jewellery' => '14-jewellery',
|
||||||
|
'Jewellery Suites' => '109-jewellery-suites',
|
||||||
|
'Necklace' => '104-necklace',
|
||||||
|
'Other' => '118-other',
|
||||||
|
'Rings' => '112-rings',
|
||||||
|
'Signet rings' => '105-signet-rings',
|
||||||
|
'Solitaire rings' => '114-solitaire-rings',
|
||||||
|
],
|
||||||
|
'Licence weapons' => [
|
||||||
|
'All' => '59-licence-weapons',
|
||||||
|
'Combi/Combo' => '63-combi-combo',
|
||||||
|
'Double express rifles' => '60-double-express-rifles',
|
||||||
|
'Rifles' => '61-rifles',
|
||||||
|
'Shotguns' => '62-shotguns',
|
||||||
|
],
|
||||||
|
'Lighting & Lamps' => [
|
||||||
|
'All' => '1-lighting-lamps',
|
||||||
|
'Candlesticks' => '4-candlesticks',
|
||||||
|
'Ceiling lights' => '3-ceiling-lights',
|
||||||
|
'Chandeliers' => '203-chandeliers',
|
||||||
|
'Floor lights' => '2-floor-lights',
|
||||||
|
'Other lighting' => '5-other-lighting',
|
||||||
|
'Table Lamps' => '125-table-lamps',
|
||||||
|
'Wall Lights' => '124-wall-lights',
|
||||||
|
],
|
||||||
|
'Mirrors' => [
|
||||||
|
'All' => '42-mirrors',
|
||||||
|
],
|
||||||
|
'Miscellaneous' => [
|
||||||
|
'All' => '43-miscellaneous',
|
||||||
|
'Fishing equipment' => '54-fishing-equipment',
|
||||||
|
'Miscellaneous' => '47-miscellaneous',
|
||||||
|
'Modern Tools' => '133-modern-tools',
|
||||||
|
'Modern consumer electronics' => '52-modern-consumer-electronics',
|
||||||
|
'Musical instruments' => '51-musical-instruments',
|
||||||
|
'Technica & Nautica' => '45-technica-nautica',
|
||||||
|
],
|
||||||
|
'Photo, Cameras & Lenses' => [
|
||||||
|
'All' => '57-photo-cameras-lenses',
|
||||||
|
'Cameras & accessories' => '71-cameras-accessories',
|
||||||
|
'Optics' => '66-optics',
|
||||||
|
'Other' => '72-other',
|
||||||
|
],
|
||||||
|
'Silver & Metals' => [
|
||||||
|
'All' => '38-silver-metals',
|
||||||
|
'Other metals' => '40-other-metals',
|
||||||
|
'Pewter, Brass & Copper' => '41-pewter-brass-copper',
|
||||||
|
'Silver' => '39-silver',
|
||||||
|
'Silver plated' => '213-silver-plated',
|
||||||
|
],
|
||||||
|
'Toys' => [
|
||||||
|
'All' => '44-toys',
|
||||||
|
'Comics' => '211-comics',
|
||||||
|
'Toys' => '212-toys',
|
||||||
|
],
|
||||||
|
'Tribal art' => [
|
||||||
|
'All' => '134-tribal-art',
|
||||||
|
],
|
||||||
|
'Vehicles, Boats & Parts' => [
|
||||||
|
'All' => '249-vehicles-boats-parts',
|
||||||
|
'Automobilia & Transport' => '255-automobilia-transport',
|
||||||
|
'Bicycles' => '132-bicycles',
|
||||||
|
'Boats & Accessories' => '250-boats-accessories',
|
||||||
|
'Car parts' => '253-car-parts',
|
||||||
|
'Cars' => '215-cars',
|
||||||
|
'Moped parts' => '254-moped-parts',
|
||||||
|
'Mopeds' => '216-mopeds',
|
||||||
|
'Motorcycle parts' => '252-motorcycle-parts',
|
||||||
|
'Motorcycles' => '251-motorcycles',
|
||||||
|
'Other' => '256-other',
|
||||||
|
],
|
||||||
|
'Vintage & Designer Fashion' => [
|
||||||
|
'All' => '49-vintage-designer-fashion',
|
||||||
|
],
|
||||||
|
'Weapons & Militaria' => [
|
||||||
|
'All' => '137-weapons-militaria',
|
||||||
|
'Airguns' => '257-airguns',
|
||||||
|
'Armour & Uniform' => '138-armour-uniform',
|
||||||
|
'Edged weapons' => '130-edged-weapons',
|
||||||
|
'Guns & Rifles' => '129-guns-rifles',
|
||||||
|
'Other' => '214-other',
|
||||||
|
],
|
||||||
|
'Wine, Port & Spirits' => [
|
||||||
|
'All' => '170-wine-port-spirits',
|
||||||
|
],
|
||||||
|
]
|
||||||
|
],
|
||||||
|
'sort_order' => [
|
||||||
|
'name' => 'Sort order',
|
||||||
|
'type' => 'list',
|
||||||
|
'values' => [
|
||||||
|
'Most bids' => 'bids_count_desc',
|
||||||
|
'Lowest bid' => 'bid_asc',
|
||||||
|
'Highest bid' => 'bid_desc',
|
||||||
|
'Last bid on' => 'bid_on',
|
||||||
|
'Ending soonest' => 'end_asc_active',
|
||||||
|
'Lowest estimate' => 'estimate_asc',
|
||||||
|
'Highest estimate' => 'estimate_desc',
|
||||||
|
'Recently added' => 'recent'
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'country' => [
|
||||||
|
'name' => 'Country',
|
||||||
|
'type' => 'list',
|
||||||
|
'values' => [
|
||||||
|
'All' => '',
|
||||||
|
'Denmark' => 'DK',
|
||||||
|
'Finland' => 'FI',
|
||||||
|
'Germany' => 'DE',
|
||||||
|
'Spain' => 'ES',
|
||||||
|
'Sweden' => 'SE',
|
||||||
|
'United Kingdom' => 'GB'
|
||||||
|
]
|
||||||
|
],
|
||||||
|
'language' => [
|
||||||
|
'name' => 'Language',
|
||||||
|
'type' => 'list',
|
||||||
|
'values' => [
|
||||||
|
'English' => 'en',
|
||||||
|
'Español' => 'es',
|
||||||
|
'Deutsch' => 'de',
|
||||||
|
'Svenska' => 'sv',
|
||||||
|
'Dansk' => 'da',
|
||||||
|
'Suomi' => 'fi',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
]];
|
||||||
|
|
||||||
|
const CACHE_TIMEOUT = 3600; // 1 hour
|
||||||
|
|
||||||
|
private $title;
|
||||||
|
|
||||||
|
public function collectData()
|
||||||
|
{
|
||||||
|
// Each page contains 48 auctions
|
||||||
|
// So we fetch 10 pages so we decrease the likelihood
|
||||||
|
// of missing auctions between feed refreshes
|
||||||
|
|
||||||
|
// Fetch first page and use that to get title
|
||||||
|
{
|
||||||
|
$url = $this->getUrl(1);
|
||||||
|
$data = getContents($url);
|
||||||
|
|
||||||
|
$title = $this->getDocumentTitle($data);
|
||||||
|
|
||||||
|
$this->items = array_merge($this->items, $this->parsePageData($data));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch remaining pages
|
||||||
|
for ($page = 2; $page <= 10; $page++) {
|
||||||
|
$url = $this->getUrl($page);
|
||||||
|
|
||||||
|
$data = getContents($url);
|
||||||
|
|
||||||
|
$this->items = array_merge($this->items, $this->parsePageData($data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return $this->title ?: parent::getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* HELPERS */
|
||||||
|
|
||||||
|
private function getUrl($page)
|
||||||
|
{
|
||||||
|
$category = $this->getInput('category');
|
||||||
|
$language = $this->getInput('language');
|
||||||
|
$sort_order = $this->getInput('sort_order');
|
||||||
|
$country = $this->getInput('country');
|
||||||
|
|
||||||
|
$url = self::URI . '/' . $language . '/search';
|
||||||
|
|
||||||
|
if ($category) {
|
||||||
|
$url = $url . '/' . $category;
|
||||||
|
}
|
||||||
|
|
||||||
|
$query = [];
|
||||||
|
$query['page'] = $page;
|
||||||
|
|
||||||
|
if ($sort_order) {
|
||||||
|
$query['order'] = $sort_order;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($country) {
|
||||||
|
$query['country_code'] = $country;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count($query) > 0) {
|
||||||
|
$url = $url . '?' . http_build_query($query);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $url;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getDocumentTitle($data)
|
||||||
|
{
|
||||||
|
$title_elem = '<title>';
|
||||||
|
$title_elem_length = strlen($title_elem);
|
||||||
|
$title_start = strpos($data, $title_elem);
|
||||||
|
$title_end = strpos($data, '</title>', $title_start);
|
||||||
|
$title_length = $title_end - $title_start + strlen($title_elem);
|
||||||
|
$title = substr($data, $title_start + strlen($title_elem), $title_length);
|
||||||
|
|
||||||
|
return $title;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The auction items data is included in the HTML document
|
||||||
|
* as a HTML entities encoded JSON structure
|
||||||
|
* which is used to hydrate the React component for the list of auctions
|
||||||
|
*/
|
||||||
|
private function parsePageData($data)
|
||||||
|
{
|
||||||
|
$key = 'data-react-props="';
|
||||||
|
$keyLength = strlen($key);
|
||||||
|
|
||||||
|
$start = strpos($data, $key);
|
||||||
|
$end = strpos($data, '"', $start + strlen($key));
|
||||||
|
$length = $end - ($start + $keyLength);
|
||||||
|
|
||||||
|
$jsonString = substr($data, $start + $keyLength, $length);
|
||||||
|
|
||||||
|
$jsonData = json_decode(htmlspecialchars_decode($jsonString), false);
|
||||||
|
|
||||||
|
$items = [];
|
||||||
|
|
||||||
|
foreach ($jsonData->{'items'} as $item) {
|
||||||
|
$title = $item->{'longTitle'};
|
||||||
|
$relative_url = $item->{'url'};
|
||||||
|
$images = $item->{'imageUrls'};
|
||||||
|
$id = $item->{'auctionId'};
|
||||||
|
|
||||||
|
$items[] = [
|
||||||
|
'title' => $title,
|
||||||
|
'uri' => self::URI . $relative_url,
|
||||||
|
'uid' => $id,
|
||||||
|
'content' => count($images) > 0 ? "<img src='$images[0]'/><br/>$title" : $title,
|
||||||
|
'enclosures' => array_slice($images, 1),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $items;
|
||||||
|
}
|
||||||
|
}
|
@ -206,7 +206,7 @@ class BukowskisBridge extends BridgeAbstract
|
|||||||
$this->items[] = [
|
$this->items[] = [
|
||||||
'title' => $title,
|
'title' => $title,
|
||||||
'uri' => $baseUrl . $relative_url,
|
'uri' => $baseUrl . $relative_url,
|
||||||
'uid' => $lot->getAttribute('data-lot-id'),
|
'uid' => $relative_url,
|
||||||
'content' => count($images) > 0 ? "<img src='$images[0]'/><br/>$title" : $title,
|
'content' => count($images) > 0 ? "<img src='$images[0]'/><br/>$title" : $title,
|
||||||
'enclosures' => array_slice($images, 1),
|
'enclosures' => array_slice($images, 1),
|
||||||
];
|
];
|
||||||
|
@ -66,7 +66,7 @@ class CarThrottleBridge extends BridgeAbstract
|
|||||||
foreach ($categoryPage->find('div.cmg-card') as $post) {
|
foreach ($categoryPage->find('div.cmg-card') as $post) {
|
||||||
$item = [];
|
$item = [];
|
||||||
|
|
||||||
$titleElement = $post->find('div.title a')[0];
|
$titleElement = $post->find('a.title')[0];
|
||||||
$post_uri = self::URI . $titleElement->getAttribute('href');
|
$post_uri = self::URI . $titleElement->getAttribute('href');
|
||||||
|
|
||||||
if (!isset($post_uri) || $post_uri == '') {
|
if (!isset($post_uri) || $post_uri == '') {
|
||||||
@ -80,8 +80,8 @@ class CarThrottleBridge extends BridgeAbstract
|
|||||||
|
|
||||||
$item['author'] = $this->parseAuthor($articlePage);
|
$item['author'] = $this->parseAuthor($articlePage);
|
||||||
|
|
||||||
$articleImage = $articlePage->find('div.block-layout-field-image')[0];
|
$articleImage = $articlePage->find('figure')[0];
|
||||||
$article = $articlePage->find('div.block-layout-body')[1];
|
$article = $articlePage->find('div.first-column div.body')[0];
|
||||||
|
|
||||||
//remove ads
|
//remove ads
|
||||||
foreach ($article->find('aside') as $ad) {
|
foreach ($article->find('aside') as $ad) {
|
||||||
|
152
bridges/CybermonitBridge.php
Executable file
152
bridges/CybermonitBridge.php
Executable file
@ -0,0 +1,152 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class CybermonitBridge extends BridgeAbstract
|
||||||
|
{
|
||||||
|
const SALT = "Mc!dks\\0#)as";
|
||||||
|
const NAME = 'Cybermonit';
|
||||||
|
const DESCRIPTION = 'Returns cybermonite CVEs, DDoS, Ransomware, Leaks, EOL, Releases';
|
||||||
|
const MAINTAINER = 'void';
|
||||||
|
|
||||||
|
const PARAMETERS = [[
|
||||||
|
'feed_type' => [
|
||||||
|
'name' => 'feed_type',
|
||||||
|
'type' => 'list',
|
||||||
|
'values' => [
|
||||||
|
'Leaks' => 'Leaks',
|
||||||
|
'CVEs' => 'CVEs',
|
||||||
|
'DDoS' => 'DDoS',
|
||||||
|
'Ransomware' => 'Ransomware',
|
||||||
|
'Releases' => 'Releases',
|
||||||
|
'EOL' => "EOL"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]];
|
||||||
|
|
||||||
|
public function getURI() {
|
||||||
|
switch ($this->getKey("feed_type")) {
|
||||||
|
case 'Leaks':
|
||||||
|
return 'https://pypbbsgyhtlerxdyfuvv.supabase.co/storage/v1/object/dane/leak.json';
|
||||||
|
break;
|
||||||
|
case 'CVEs':
|
||||||
|
return 'https://pypbbsgyhtlerxdyfuvv.supabase.co/storage/v1/object/dane/2025.json';
|
||||||
|
break;
|
||||||
|
case 'DDoS':
|
||||||
|
return 'https://pypbbsgyhtlerxdyfuvv.supabase.co/storage/v1/object/dane/ddos.json';
|
||||||
|
break;
|
||||||
|
case 'Ransomware':
|
||||||
|
return 'https://pypbbsgyhtlerxdyfuvv.supabase.co/storage/v1/object/dane/ransomware.json';
|
||||||
|
break;
|
||||||
|
case 'EOL':
|
||||||
|
return 'https://pypbbsgyhtlerxdyfuvv.supabase.co/storage/v1/object/dane/eol.json';
|
||||||
|
break;
|
||||||
|
case 'Releases':
|
||||||
|
return 'https://pypbbsgyhtlerxdyfuvv.supabase.co/storage/v1/object/dane/releases.json';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return 'https://cybermonit.com';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function collectData()
|
||||||
|
{
|
||||||
|
$opts = array(
|
||||||
|
'accept: */*',
|
||||||
|
'apikey: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InB5cGJic2d5aHRsZXJ4ZHlmdXZ2Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3NDAxMjUwNzAsImV4cCI6MjA1NTcwMTA3MH0.xmcCqJUgvRtVsp6XmaH1YmUeerqZRZNQ_XmCnpOEFAo',
|
||||||
|
'authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InB5cGJic2d5aHRsZXJ4ZHlmdXZ2Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3NDAxMjUwNzAsImV4cCI6MjA1NTcwMTA3MH0.xmcCqJUgvRtVsp6XmaH1YmUeerqZRZNQ_XmCnpOEFAo',
|
||||||
|
'origin: https://cybermonit.com',
|
||||||
|
'referer: https://cybermonit.com',
|
||||||
|
'user-agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) QtWebEngine/6.8.2 Chrome/122.0.6261.171 Safari/537.36',
|
||||||
|
'x-client-info: supabase-js-web/2.49.1',
|
||||||
|
);
|
||||||
|
$html = getContents($this->getURI(), $opts);
|
||||||
|
$data = json_decode($html, true);
|
||||||
|
array_walk_recursive($data, function(&$item, $key) {
|
||||||
|
$item = htmlspecialchars($item);
|
||||||
|
});
|
||||||
|
|
||||||
|
switch ($this->getKey("feed_type")) {
|
||||||
|
case 'Leaks':
|
||||||
|
foreach ($data as $obj) {
|
||||||
|
$this->items[] = [
|
||||||
|
'title' => sprintf("%s - %s", empty($obj['domain']) ? 'Unknown' : $obj['domain'], $obj['data_leaked']),
|
||||||
|
'timestamp' => $obj['breach_date'],
|
||||||
|
'uri' => "https://cybermonit.com/leaks",
|
||||||
|
'categories' => ['leaks'],
|
||||||
|
'content' => $obj['description'],
|
||||||
|
'uid' => sha1(sprintf("%s.%s.%s", $obj['domain'], $obj['breach_date'], self::SALT))
|
||||||
|
];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'CVEs':
|
||||||
|
foreach ($data as $obj) {
|
||||||
|
$this->items[] = [
|
||||||
|
'title' => sprintf("%s (%s %s) - %s", $obj['cve_id'], $obj['score'], $obj['severity_en'], substr($obj['description'], 0, 150).'[...]'),
|
||||||
|
'timestamp' => $obj['publishedDate'],
|
||||||
|
'uri' => "https://cybermonit.com/cve",
|
||||||
|
"categories" => ['CVEs'],
|
||||||
|
'content' => $obj['description'],
|
||||||
|
'uid' => sha1(sprintf("%s.%s.%s", $obj['cve_id'], $obj['publishedDate'], self::SALT))
|
||||||
|
];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'DDoS':
|
||||||
|
foreach ($data['targets'] as $obj) {
|
||||||
|
$this->items[] = [
|
||||||
|
'title' => sprintf("%s", $obj['host']),
|
||||||
|
'timestamp' => null,
|
||||||
|
'uri' => "https://cybermonit.com/ddos",
|
||||||
|
"categories" => ['DDoS'],
|
||||||
|
"content" => sprintf("IP: %s<br/>Type: %s<br>Method: %s<br>Port: %s<br>Use SSL: %s", $obj['ip'], $obj['type'], $obj['method'], $obj['port'], $obj['use_ssl'] == 1 ? "True" : "False"),
|
||||||
|
'uid' => sha1(sprintf("%s.%s.%s", $obj['host'], $obj['ip'], self::SALT))
|
||||||
|
];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'Ransomware':
|
||||||
|
foreach ($data as $obj) {
|
||||||
|
$this->items[] = [
|
||||||
|
'title' => sprintf("%s attack on %s (%s)", $obj['group'], $obj['victim'], $obj['country']),
|
||||||
|
'timestamp' => $obj['attackdate'],
|
||||||
|
"categories" => ['Ransomware', $obj['group']],
|
||||||
|
'uri' => "https://cybermonit.com/ransomware",
|
||||||
|
"content" => "Ransomware attack ({$obj['group']}) on {$obj['victim']}, country: {$obj['country']}",
|
||||||
|
'uid' => sha1(sprintf("%s.%s.%s", $obj['victim'], $obj['attackdate'], self::SALT))
|
||||||
|
];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'Releases':
|
||||||
|
foreach ($data as $obj) {
|
||||||
|
$this->items[] = [
|
||||||
|
'title' => sprintf("%s %s", $obj['nazwa_projektu'], $obj['wersja']),
|
||||||
|
'timestamp' => $obj['data_wydania'],
|
||||||
|
'categories' => ['Releases'],
|
||||||
|
'uri' => $obj['url_zdjecia'],
|
||||||
|
'content' => sprintf("%s updated to version %s. Project URL: %s, Release notes: %s", $obj['nazwa_projektu'], $obj['wersja'], $obj['url_projektu'], $obj['url_zdjecia']),
|
||||||
|
'uid' => sha1(sprintf("%s.%s.%s", $obj['nazwa_projektu'], $obj['data_wydania'], self::SALT))
|
||||||
|
];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'EOL':
|
||||||
|
foreach ($data as $key => $v) {
|
||||||
|
$val = $v[0];
|
||||||
|
$this->items[] = [
|
||||||
|
'title' => sprintf("%s %s %s", $key, $val['cycle'], $val['lts'] == true ? 'LTS' : ''),
|
||||||
|
'timestamp'=> null,
|
||||||
|
'categories'=> ['EOL'],
|
||||||
|
'uri' => $this->getURI(),
|
||||||
|
'content' => sprintf("Product: %s<br>Version: %s<br>Release date: %s<br>End of life: %s", $key, $val['cycle'], $val['releaseDate'], $val['eol']),
|
||||||
|
'uid' => sha1(sprintf("%s.%s.%s", $key, $val['eol'], self::SALT))
|
||||||
|
];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
usort($this->items, function($a, $b) {
|
||||||
|
if ($a['timestamp'] == $b['timestamp']) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return ($a['timestamp'] > $b['timestamp']) ? -1 : 1;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -48,6 +48,16 @@ https://www.dealabs.com/groupe/abonnements-internet?sortBy=lowest_price
|
|||||||
Il faut alors saisir :
|
Il faut alors saisir :
|
||||||
abonnements-internet',
|
abonnements-internet',
|
||||||
],
|
],
|
||||||
|
'subgroups' => [
|
||||||
|
'name' => 'Catégorie',
|
||||||
|
'type' => 'text',
|
||||||
|
'exampleValue' => '1071',
|
||||||
|
'title' => 'Numéro du ou des catégories dans l\'URL : Il faut entrer le ou les numéros de catégories qui sont présent après "groups=" et avant tout éventuel "&"
|
||||||
|
Exemple : Si l\'URL du groupe affichées dans le navigateur est :
|
||||||
|
https://www.dealabs.com/groupe/telecommunications?groups=1071%2C1070&sortBy=new
|
||||||
|
Il faut alors saisir :
|
||||||
|
1071%2C1070',
|
||||||
|
],
|
||||||
'order' => [
|
'order' => [
|
||||||
'name' => 'Trier par',
|
'name' => 'Trier par',
|
||||||
'type' => 'list',
|
'type' => 'list',
|
||||||
@ -88,6 +98,7 @@ abonnements-internet',
|
|||||||
'uri-group' => 'groupe/',
|
'uri-group' => 'groupe/',
|
||||||
'uri-deal' => 'bons-plans/',
|
'uri-deal' => 'bons-plans/',
|
||||||
'uri-merchant' => 'search/bons-plans?merchant-id=',
|
'uri-merchant' => 'search/bons-plans?merchant-id=',
|
||||||
|
'image-host' => 'https://static-pepper.dealabs.com/',
|
||||||
'request-error' => 'Impossible de joindre Dealabs',
|
'request-error' => 'Impossible de joindre Dealabs',
|
||||||
'thread-error' => 'Impossible de déterminer l\'ID de la discussion. Vérifiez l\'URL que vous avez entré',
|
'thread-error' => 'Impossible de déterminer l\'ID de la discussion. Vérifiez l\'URL que vous avez entré',
|
||||||
'currency' => '€',
|
'currency' => '€',
|
||||||
|
50
bridges/FeedProxyBridge.php
Executable file
50
bridges/FeedProxyBridge.php
Executable file
@ -0,0 +1,50 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class FeedProxyBridge extends FeedExpander
|
||||||
|
{
|
||||||
|
const MAINTAINER = 'void';
|
||||||
|
const NAME = 'FeedProxy';
|
||||||
|
const URI = '';
|
||||||
|
const DESCRIPTION = <<<'TEXT'
|
||||||
|
This bridge simply parse an external RSS<br>
|
||||||
|
TEXT;
|
||||||
|
|
||||||
|
const PARAMETERS = [
|
||||||
|
[
|
||||||
|
'feed_name' => [
|
||||||
|
'name' => 'Feed name',
|
||||||
|
'type' => 'text',
|
||||||
|
'exampleValue' => 'FeedProxy',
|
||||||
|
],
|
||||||
|
'feed_1' => [
|
||||||
|
'name' => 'Feed url',
|
||||||
|
'type' => 'text',
|
||||||
|
'required' => true,
|
||||||
|
'exampleValue' => 'https://lorem-rss.herokuapp.com/feed?unit=day'
|
||||||
|
],
|
||||||
|
'limit' => self::LIMIT,
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: Consider a strategy which produces a shorter feed url
|
||||||
|
*/
|
||||||
|
public function collectData()
|
||||||
|
{
|
||||||
|
$limit = (int)($this->getInput('limit') ?: 99);
|
||||||
|
$feed = $this->getInput('feed_1');
|
||||||
|
$this->collectExpandableDatas($feed, $limit);
|
||||||
|
|
||||||
|
// Sort by timestamp, uri, title in descending order
|
||||||
|
usort($this->items, function ($a, $b) {
|
||||||
|
$t1 = $a['timestamp'] ?? $a['uri'] ?? $a['title'];
|
||||||
|
$t2 = $b['timestamp'] ?? $b['uri'] ?? $b['title'];
|
||||||
|
return $t2 <=> $t1;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return $this->getInput('feed_name') ?: 'FeedProxy';
|
||||||
|
}
|
||||||
|
}
|
@ -3,7 +3,8 @@
|
|||||||
class FreeTelechargerBridge extends BridgeAbstract
|
class FreeTelechargerBridge extends BridgeAbstract
|
||||||
{
|
{
|
||||||
const NAME = 'Free-Telecharger';
|
const NAME = 'Free-Telecharger';
|
||||||
const URI = 'https://www.free-telecharger.art/';
|
const URI = 'https://www.free-telecharger.fun/';
|
||||||
|
const ALTERNATEURI = 'https://www.free-telecharger.com/';
|
||||||
const DESCRIPTION = 'Suivi de série sur Free-Telecharger';
|
const DESCRIPTION = 'Suivi de série sur Free-Telecharger';
|
||||||
const MAINTAINER = 'sysadminstory';
|
const MAINTAINER = 'sysadminstory';
|
||||||
const PARAMETERS = [
|
const PARAMETERS = [
|
||||||
@ -12,19 +13,19 @@ class FreeTelechargerBridge extends BridgeAbstract
|
|||||||
'name' => 'URL de la série',
|
'name' => 'URL de la série',
|
||||||
'type' => 'text',
|
'type' => 'text',
|
||||||
'required' => true,
|
'required' => true,
|
||||||
'title' => 'URL d\'une série sans le https://www.free-telecharger.art/',
|
'title' => 'URL d\'une série sans le https://www.free-telecharger.fun/',
|
||||||
'pattern' => 'series.*\.html',
|
'pattern' => 'series.*\.html',
|
||||||
'exampleValue' => 'series-vf-hd/151432-wolf-saison-1-complete-web-dl-720p.html'
|
'exampleValue' => 'series-vf-hd/151432-wolf-saison-1-complete-web-dl-720p.html'
|
||||||
],
|
],
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
const CACHE_TIMEOUT = 3600;
|
const CACHE_TIMEOUT = 3600;
|
||||||
private string $showTitle;
|
private string $showTitle = '';
|
||||||
private string $showTechDetails;
|
private string $showTechDetails = '';
|
||||||
|
|
||||||
public function collectData()
|
public function collectData()
|
||||||
{
|
{
|
||||||
$html = getSimpleHTMLDOM(self::URI . $this->getInput('url'));
|
$html = getSimpleHTMLDOM(self::ALTERNATEURI . $this->getInput('url'));
|
||||||
|
|
||||||
// Find all block content of the page
|
// Find all block content of the page
|
||||||
$blocks = $html->find('div[class=block1]');
|
$blocks = $html->find('div[class=block1]');
|
||||||
|
@ -192,15 +192,18 @@ class GithubIssueBridge extends BridgeAbstract
|
|||||||
|
|
||||||
public function collectData()
|
public function collectData()
|
||||||
{
|
{
|
||||||
$html = getSimpleHTMLDOM($this->getURI());
|
$url = $this->getURI();
|
||||||
|
$html = getSimpleHTMLDOM($url);
|
||||||
|
|
||||||
switch ($this->queriedContext) {
|
switch ($this->queriedContext) {
|
||||||
case static::BRIDGE_OPTIONS[1]: // Issue comments
|
case static::BRIDGE_OPTIONS[1]: // Issue comments
|
||||||
$this->items = $this->extractIssueComments($html);
|
$this->items = $this->extractIssueComments($html);
|
||||||
break;
|
break;
|
||||||
case static::BRIDGE_OPTIONS[0]: // Project Issues
|
case static::BRIDGE_OPTIONS[0]: // Project Issues
|
||||||
foreach ($html->find('.js-active-navigation-container .js-navigation-item') as $issue) {
|
$issues = $html->find('.js-active-navigation-container .js-navigation-item');
|
||||||
$info = $issue->find('.opened-by', 0);
|
$issues = $html->find('.IssueRow-module__row--XmR1f');
|
||||||
|
foreach ($issues as $issue) {
|
||||||
|
$info = $issue->find('.issue-item-module__authorCreatedLink--wFZvk', 0);
|
||||||
|
|
||||||
preg_match('/\/([0-9]+)$/', $issue->find('a', 0)->href, $match);
|
preg_match('/\/([0-9]+)$/', $issue->find('a', 0)->href, $match);
|
||||||
$issueNbr = $match[1];
|
$issueNbr = $match[1];
|
||||||
@ -222,24 +225,24 @@ class GithubIssueBridge extends BridgeAbstract
|
|||||||
$item['content'] = 'Can not extract comments from ' . $uri;
|
$item['content'] = 'Can not extract comments from ' . $uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
$item['author'] = $info->find('a', 0)->plaintext;
|
$item['author'] = $issue->find('a', 1)->plaintext;
|
||||||
$item['timestamp'] = strtotime(
|
$item['timestamp'] = strtotime(
|
||||||
$info->find('relative-time', 0)->getAttribute('datetime')
|
$issue->find('relative-time', 0)->getAttribute('datetime')
|
||||||
);
|
);
|
||||||
$item['title'] = html_entity_decode(
|
$item['title'] = html_entity_decode(
|
||||||
$issue->find('.js-navigation-open', 0)->plaintext,
|
$issue->find('h3', 0)->plaintext,
|
||||||
ENT_QUOTES,
|
ENT_QUOTES,
|
||||||
'UTF-8'
|
'UTF-8'
|
||||||
);
|
);
|
||||||
|
|
||||||
$comment_count = 0;
|
//$comment_count = 0;
|
||||||
if ($span = $issue->find('a[aria-label*="comment"] span', 0)) {
|
//if ($span = $issue->find('a[aria-label*="comment"] span', 0)) {
|
||||||
$comment_count = $span->plaintext;
|
// $comment_count = $span->plaintext;
|
||||||
}
|
//}
|
||||||
|
|
||||||
$item['content'] .= "\n" . 'Comments: ' . $comment_count;
|
//$item['content'] .= "\n" . 'Comments: ' . $comment_count;
|
||||||
$item['uri'] = self::URI
|
$item['uri'] = self::URI
|
||||||
. trim($issue->find('.js-navigation-open', 0)->getAttribute('href'), '/');
|
. trim($issue->find('a', 0)->getAttribute('href'), '/');
|
||||||
$this->items[] = $item;
|
$this->items[] = $item;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
class GovTrackBridge extends BridgeAbstract
|
class GovTrackBridge extends FeedExpander
|
||||||
{
|
{
|
||||||
const NAME = 'GovTrack';
|
const NAME = 'GovTrack';
|
||||||
const MAINTAINER = 'phantop';
|
const MAINTAINER = 'phantop';
|
||||||
@ -18,7 +18,7 @@ class GovTrackBridge extends BridgeAbstract
|
|||||||
'Major Legislative Activity' => 'major-bill-activity',
|
'Major Legislative Activity' => 'major-bill-activity',
|
||||||
'New Bills and Resolutions' => 'introduced-bills',
|
'New Bills and Resolutions' => 'introduced-bills',
|
||||||
'New Laws' => 'enacted-bills',
|
'New Laws' => 'enacted-bills',
|
||||||
'Posts from Us' => 'posts'
|
'News from Us' => 'posts'
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
'limit' => self::LIMIT
|
'limit' => self::LIMIT
|
||||||
@ -26,56 +26,42 @@ class GovTrackBridge extends BridgeAbstract
|
|||||||
|
|
||||||
public function collectData()
|
public function collectData()
|
||||||
{
|
{
|
||||||
$html = getSimpleHTMLDOMCached($this->getURI());
|
$limit = $this->getInput('limit') ?? 15;
|
||||||
if ($this->getInput('feed') != 'posts') {
|
if ($this->getInput('feed') == 'posts') {
|
||||||
$this->collectEvent($html);
|
$this->collectExpandableDatas($this->getURI() . '.rss', $limit);
|
||||||
return;
|
} else {
|
||||||
|
$this->collectEvent($this->getURI(), $limit);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$html = defaultLinkTo($html, parent::getURI());
|
protected function parseItem(array $item)
|
||||||
$limit = $this->getInput('limit') ?? 10;
|
{
|
||||||
foreach ($html->find('section') as $element) {
|
|
||||||
if (--$limit == 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
$info = explode(' ', $element->find('p', 0)->innertext);
|
|
||||||
$item = [
|
|
||||||
'categories' => [implode(' ', array_slice($info, 4))],
|
|
||||||
'timestamp' => strtotime(implode(' ', array_slice($info, 0, 3))),
|
|
||||||
'title' => $element->find('a', 0)->innertext,
|
|
||||||
'uri' => $element->find('a', 0)->href,
|
|
||||||
];
|
|
||||||
|
|
||||||
$html = getSimpleHTMLDOMCached($item['uri']);
|
$html = getSimpleHTMLDOMCached($item['uri']);
|
||||||
$html = defaultLinkTo($html, parent::getURI());
|
$html = defaultLinkTo($html, parent::getURI());
|
||||||
|
|
||||||
|
$item['categories'] = [$html->find('.breadcrumb-item', 1)->plaintext];
|
||||||
$content = $html->find('#content .col-md', 1);
|
$content = $html->find('#content .col-md', 1);
|
||||||
$info = explode(' by ', $content->find('p', 0)->plaintext);
|
$item['author'] = explode(' by ', $content->firstChild()->plaintext)[1];
|
||||||
$content->removeChild($content->firstChild());
|
$content->removeChild($content->firstChild());
|
||||||
|
|
||||||
$item['author'] = implode(' ', array_slice($info, 1));
|
|
||||||
$item['content'] = $content->innertext;
|
$item['content'] = $content->innertext;
|
||||||
|
|
||||||
$this->items[] = $item;
|
return $item;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function collectEvent($html)
|
private function collectEvent($uri, $limit)
|
||||||
{
|
{
|
||||||
$opt = [];
|
$html = getSimpleHTMLDOMCached($uri);
|
||||||
preg_match('/"csrfmiddlewaretoken" value="(.*)"/', $html, $opt);
|
preg_match('/"csrfmiddlewaretoken" value="(.*)"/', $html, $preg);
|
||||||
$header = [
|
$header = [
|
||||||
"cookie: csrftoken=$opt[1]",
|
"cookie: csrftoken=$preg[1]",
|
||||||
"x-csrftoken: $opt[1]",
|
"x-csrftoken: $preg[1]",
|
||||||
'referer: ' . parent::getURI(),
|
'referer: ' . parent::getURI(),
|
||||||
];
|
];
|
||||||
preg_match('/var selected_feed = "(.*)";/', $html, $opt);
|
preg_match('/var selected_feed = "(.*)";/', $html, $preg);
|
||||||
$post = [
|
$opt = [ CURLOPT_POSTFIELDS => [
|
||||||
'count' => $this->getInput('limit') ?? 20,
|
'count' => $limit,
|
||||||
'feed' => $opt[1]
|
'feed' => $preg[1]
|
||||||
];
|
]];
|
||||||
$opt = [ CURLOPT_POSTFIELDS => $post ];
|
|
||||||
|
|
||||||
$html = getContents(parent::getURI() . 'events/_load_events', $header, $opt);
|
$html = getContents(parent::getURI() . 'events/_load_events', $header, $opt);
|
||||||
$html = defaultLinkTo(str_get_html($html), parent::getURI());
|
$html = defaultLinkTo(str_get_html($html), parent::getURI());
|
||||||
@ -83,10 +69,10 @@ class GovTrackBridge extends BridgeAbstract
|
|||||||
foreach ($html->find('.tracked_event') as $event) {
|
foreach ($html->find('.tracked_event') as $event) {
|
||||||
$bill = $event->find('.event_title a, .event_body a', 0);
|
$bill = $event->find('.event_title a, .event_body a', 0);
|
||||||
$date = explode(' ', $event->find('.event_date', 0)->plaintext);
|
$date = explode(' ', $event->find('.event_date', 0)->plaintext);
|
||||||
preg_match('/Sponsor:(.*)\n/', $event->plaintext, $opt);
|
preg_match('/Sponsor:(.*)\n/', $event->plaintext, $preg);
|
||||||
|
|
||||||
$item = [
|
$item = [
|
||||||
'author' => $opt[1] ?? '',
|
'author' => $preg[1] ?? '',
|
||||||
'content' => $event->find('td', 1)->innertext,
|
'content' => $event->find('td', 1)->innertext,
|
||||||
'enclosures' => [$event->find('img', 0)->src],
|
'enclosures' => [$event->find('img', 0)->src],
|
||||||
'timestamp' => strtotime(implode(' ', array_slice($date, 2))),
|
'timestamp' => strtotime(implode(' ', array_slice($date, 2))),
|
||||||
@ -115,10 +101,10 @@ class GovTrackBridge extends BridgeAbstract
|
|||||||
|
|
||||||
public function getURI()
|
public function getURI()
|
||||||
{
|
{
|
||||||
if ($this->getInput('feed') != 'posts') {
|
if ($this->getInput('feed') == 'posts') {
|
||||||
$url = parent::getURI() . 'events/' . $this->getInput('feed');
|
|
||||||
} else {
|
|
||||||
$url = parent::getURI() . $this->getInput('feed');
|
$url = parent::getURI() . $this->getInput('feed');
|
||||||
|
} else {
|
||||||
|
$url = parent::getURI() . 'events/' . $this->getInput('feed');
|
||||||
}
|
}
|
||||||
return $url;
|
return $url;
|
||||||
}
|
}
|
||||||
|
@ -47,6 +47,16 @@ Example: If the URL of the group displayed in the browser is :
|
|||||||
https://www.hotukdeals.com/tag/broadband?sortBy=temp
|
https://www.hotukdeals.com/tag/broadband?sortBy=temp
|
||||||
Then enter :
|
Then enter :
|
||||||
broadband',
|
broadband',
|
||||||
|
],
|
||||||
|
'subgroups' => [
|
||||||
|
'name' => 'category',
|
||||||
|
'type' => 'text',
|
||||||
|
'exampleValue' => '343563',
|
||||||
|
'title' => 'Category number in the URL : The category number that must be entered is present after "groups=" and before any "&".
|
||||||
|
Example: If the URL of the group displayed in the browser is :
|
||||||
|
https://www.hotukdeals.com/tag/broadband?groups=343563&sortBy=new
|
||||||
|
Then enter :
|
||||||
|
343563',
|
||||||
],
|
],
|
||||||
'order' => [
|
'order' => [
|
||||||
'name' => 'Order by',
|
'name' => 'Order by',
|
||||||
@ -86,6 +96,7 @@ broadband',
|
|||||||
'uri-group' => 'tag/',
|
'uri-group' => 'tag/',
|
||||||
'uri-deal' => 'deals/',
|
'uri-deal' => 'deals/',
|
||||||
'uri-merchant' => 'search/deals?merchant-id=',
|
'uri-merchant' => 'search/deals?merchant-id=',
|
||||||
|
'image-host' => 'https://images.hotukdeals.com/',
|
||||||
'request-error' => 'Could not request HotUKDeals',
|
'request-error' => 'Could not request HotUKDeals',
|
||||||
'thread-error' => 'Unable to determine the thread ID. Check the URL you entered',
|
'thread-error' => 'Unable to determine the thread ID. Check the URL you entered',
|
||||||
'currency' => '£',
|
'currency' => '£',
|
||||||
|
@ -86,6 +86,11 @@ class InstagramBridge extends BridgeAbstract
|
|||||||
$headers = [];
|
$headers = [];
|
||||||
$sessionId = $this->getOption('session_id');
|
$sessionId = $this->getOption('session_id');
|
||||||
$dsUserId = $this->getOption('ds_user_id');
|
$dsUserId = $this->getOption('ds_user_id');
|
||||||
|
$headers[] = 'x-ig-app-id: 936619743392459';
|
||||||
|
$headers[] = 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36';
|
||||||
|
$headers[] = 'Accept-Language: en-US,en;q=0.9,ru;q=0.8';
|
||||||
|
$headers[] = 'Accept-Encoding: gzip, deflate, br';
|
||||||
|
$headers[] = 'Accept: */*';
|
||||||
if ($sessionId and $dsUserId) {
|
if ($sessionId and $dsUserId) {
|
||||||
$headers[] = 'cookie: sessionid=' . $sessionId . '; ds_user_id=' . $dsUserId;
|
$headers[] = 'cookie: sessionid=' . $sessionId . '; ds_user_id=' . $dsUserId;
|
||||||
}
|
}
|
||||||
@ -125,8 +130,10 @@ class InstagramBridge extends BridgeAbstract
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_null($this->getInput('u'))) {
|
if (!is_null($this->getInput('u')) && !$this->fallbackMode) {
|
||||||
$userMedia = $data->data->user->edge_owner_to_timeline_media->edges;
|
$userMedia = $data->data->user->edge_owner_to_timeline_media->edges;
|
||||||
|
} elseif (!is_null($this->getInput('u')) && $this->fallbackMode) {
|
||||||
|
$userMedia = $data->context->graphql_media;
|
||||||
} elseif (!is_null($this->getInput('h'))) {
|
} elseif (!is_null($this->getInput('h'))) {
|
||||||
$userMedia = $data->data->hashtag->edge_hashtag_to_media->edges;
|
$userMedia = $data->data->hashtag->edge_hashtag_to_media->edges;
|
||||||
} elseif (!is_null($this->getInput('l'))) {
|
} elseif (!is_null($this->getInput('l'))) {
|
||||||
@ -134,7 +141,12 @@ class InstagramBridge extends BridgeAbstract
|
|||||||
}
|
}
|
||||||
|
|
||||||
foreach ($userMedia as $media) {
|
foreach ($userMedia as $media) {
|
||||||
|
// The media is not in the same element if in fallback mode than not
|
||||||
|
if (!$this->fallbackMode) {
|
||||||
$media = $media->node;
|
$media = $media->node;
|
||||||
|
} else {
|
||||||
|
$media = $media->shortcode_media;
|
||||||
|
}
|
||||||
|
|
||||||
switch ($this->getInput('media_type')) {
|
switch ($this->getInput('media_type')) {
|
||||||
case 'all':
|
case 'all':
|
||||||
@ -267,7 +279,10 @@ class InstagramBridge extends BridgeAbstract
|
|||||||
|
|
||||||
protected function getInstagramJSON($uri)
|
protected function getInstagramJSON($uri)
|
||||||
{
|
{
|
||||||
|
// Sets fallbackMode to false
|
||||||
|
$this->fallbackMode = false;
|
||||||
if (!is_null($this->getInput('u'))) {
|
if (!is_null($this->getInput('u'))) {
|
||||||
|
try {
|
||||||
$userId = $this->getInstagramUserId($this->getInput('u'));
|
$userId = $this->getInstagramUserId($this->getInput('u'));
|
||||||
$data = $this->getContents(self::URI .
|
$data = $this->getContents(self::URI .
|
||||||
'graphql/query/?query_hash=' .
|
'graphql/query/?query_hash=' .
|
||||||
@ -275,6 +290,28 @@ class InstagramBridge extends BridgeAbstract
|
|||||||
'&variables={"id"%3A"' .
|
'&variables={"id"%3A"' .
|
||||||
$userId .
|
$userId .
|
||||||
'"%2C"first"%3A10}');
|
'"%2C"first"%3A10}');
|
||||||
|
} catch (HttpException $e) {
|
||||||
|
// If loading the data directly failed, we fall back to the "/embed" data loading
|
||||||
|
// We are in the fallback mode : set a booolean to handle this specific case while collecting the content
|
||||||
|
$this->fallbackMode = true;
|
||||||
|
// Get the HTML code of the profile embed page, and extract the JSON of it
|
||||||
|
$username = $this->getInput('u');
|
||||||
|
// Load the content using the integrated function to use helping headers
|
||||||
|
$htmlString = $this->getContents(self::URI . $username . '/embed/');
|
||||||
|
// Load the String as an SimpleHTMLDom Object
|
||||||
|
$html = new simple_html_dom();
|
||||||
|
$html->load($htmlString);
|
||||||
|
// Find the <script> tag containing the JSON content
|
||||||
|
$jsCode = $html->find('body', 0)->find('script', 3)->innertext;
|
||||||
|
|
||||||
|
// Extract the content needed by our bridge of the whole Javascript content
|
||||||
|
$regex = '#"contextJSON":"(.*)"}\]\],\["NavigationMetrics"#m';
|
||||||
|
preg_match($regex, $jsCode, $matches);
|
||||||
|
$jsVariable = $matches[1];
|
||||||
|
$data = stripcslashes($jsVariable);
|
||||||
|
// stripcslashes remove Javascript unicode escaping : add it back to the string so json_decode can handle it
|
||||||
|
$data = preg_replace('/(?<!\\\\)u[0-9A-Fa-f]{4}/', '\\\\$0', $data);
|
||||||
|
}
|
||||||
return json_decode($data);
|
return json_decode($data);
|
||||||
} elseif (!is_null($this->getInput('h'))) {
|
} elseif (!is_null($this->getInput('h'))) {
|
||||||
$data = $this->getContents(self::URI .
|
$data = $this->getContents(self::URI .
|
||||||
|
118
bridges/LeagueOfLegendsNewsBridge.php
Normal file
118
bridges/LeagueOfLegendsNewsBridge.php
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class LeagueOfLegendsNewsBridge extends BridgeAbstract
|
||||||
|
{
|
||||||
|
const NAME = 'League of Legends News';
|
||||||
|
const URI = 'https://www.leagueoflegends.com';
|
||||||
|
const DESCRIPTION = 'Official League of Legends news.';
|
||||||
|
const MAINTAINER = 'KappaPrajd';
|
||||||
|
const PARAMETERS = [
|
||||||
|
[
|
||||||
|
'language' => [
|
||||||
|
'name' => 'Language',
|
||||||
|
'type' => 'list',
|
||||||
|
'defaultValue' => 'en-us',
|
||||||
|
'values' => [
|
||||||
|
'English (NA)' => 'en-us',
|
||||||
|
'English (EUW)' => 'en-gb',
|
||||||
|
'Deutsch' => 'de-de',
|
||||||
|
'Español (EUW)' => 'es-es',
|
||||||
|
'Français' => 'fr-fr',
|
||||||
|
'Italiano' => 'it-it',
|
||||||
|
'Polski' => 'pl-pl',
|
||||||
|
'Ελληνικά' => 'el-gr',
|
||||||
|
'Română' => 'ro-ro',
|
||||||
|
'Magyar' => 'hu-hu',
|
||||||
|
'Čeština' => 'cs-cz',
|
||||||
|
'Español (LATAM)' => 'es-mx',
|
||||||
|
'Português' => 'pt-br',
|
||||||
|
'日本語' => 'ja-jp',
|
||||||
|
'Русский' => 'ru-ru',
|
||||||
|
'Türkçe' => 'tr-tr',
|
||||||
|
'English (OCE)' => 'en-au',
|
||||||
|
'한국어' => 'ko-kr',
|
||||||
|
'English (SG)' => 'en-sg',
|
||||||
|
'English (PH)' => 'en-ph',
|
||||||
|
'Tiếng Việt' => 'vi-vn',
|
||||||
|
'ภาษาไทย' => 'th-th',
|
||||||
|
'繁體中文' => 'zh-tw',
|
||||||
|
'العربية' => 'ar-ae'
|
||||||
|
]
|
||||||
|
],
|
||||||
|
'category' => [
|
||||||
|
'name' => 'Category',
|
||||||
|
'type' => 'list',
|
||||||
|
'defaultValue' => 'all',
|
||||||
|
'values' => [
|
||||||
|
'All' => 'all',
|
||||||
|
'Game updates' => 'game-updates',
|
||||||
|
'Esports' => 'esports',
|
||||||
|
'Dev' => 'dev',
|
||||||
|
'Lore' => 'lore',
|
||||||
|
'Media' => 'media',
|
||||||
|
'Merch' => 'merch',
|
||||||
|
'Community' => 'community',
|
||||||
|
'Riot Games' => 'riot-games'
|
||||||
|
]
|
||||||
|
],
|
||||||
|
'onlyPatchNotes' => [
|
||||||
|
'name' => 'Only patch notes',
|
||||||
|
'type' => 'checkbox',
|
||||||
|
'defaultValue' => false,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
];
|
||||||
|
|
||||||
|
public function collectData()
|
||||||
|
{
|
||||||
|
$siteUrl = $this->getSiteUrl();
|
||||||
|
$html = getSimpleHTMLDOM($siteUrl);
|
||||||
|
|
||||||
|
$articles = $html->find('a[data-testid=articlefeaturedcard-component]');
|
||||||
|
|
||||||
|
foreach ($articles as $article) {
|
||||||
|
$title = $article->find('div[data-testid=card-title]', 0)->plaintext;
|
||||||
|
$content = $article->find('div[data-testid=card-description] div div div', 0)->plaintext;
|
||||||
|
$timestamp = $article->find('div[data-testid=card-date] time', 0)->getAttribute('datetime');
|
||||||
|
$href = $article->getAttribute('href');
|
||||||
|
|
||||||
|
$item = [
|
||||||
|
'title' => $title,
|
||||||
|
'content' => $content,
|
||||||
|
'timestamp' => $timestamp,
|
||||||
|
'uri' => $this->getArticleUri($href),
|
||||||
|
];
|
||||||
|
|
||||||
|
$this->items[] = $item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getSiteUrl()
|
||||||
|
{
|
||||||
|
$lang = $this->getInput('language');
|
||||||
|
$category = $this->getInput('category');
|
||||||
|
$onlyPatchNotes = $this->getInput('onlyPatchNotes');
|
||||||
|
|
||||||
|
$url = self::URI . '/' . $lang . '/news';
|
||||||
|
|
||||||
|
if ($onlyPatchNotes) {
|
||||||
|
return $url . '/tags/patch-notes';
|
||||||
|
} else if ($category === 'all') {
|
||||||
|
return $url;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $url . '/' . $category;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getArticleUri($href)
|
||||||
|
{
|
||||||
|
$isInternalLink = str_starts_with($href, '/');
|
||||||
|
|
||||||
|
if ($isInternalLink) {
|
||||||
|
return self::URI . $href;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $href;
|
||||||
|
}
|
||||||
|
}
|
@ -78,8 +78,8 @@ class LfcPlBridge extends BridgeAbstract
|
|||||||
|
|
||||||
foreach ($commentsDom as $comment) {
|
foreach ($commentsDom as $comment) {
|
||||||
$header = $comment->find('.header', 0)->plaintext;
|
$header = $comment->find('.header', 0)->plaintext;
|
||||||
$content = $comment->find('.content', 0)->plaintext;
|
$commentContent = $comment->find('.content', 0)->plaintext;
|
||||||
$comments .= $header . '<br />' . $content . '<br /><br />';
|
$comments .= $header . '<br />' . $commentContent . '<br /><br />';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,6 +48,16 @@ https://www.mydealz.de/gruppe/dsl?sortBy=temp
|
|||||||
Dann geben Sie ein:
|
Dann geben Sie ein:
|
||||||
dsl',
|
dsl',
|
||||||
],
|
],
|
||||||
|
'subgroups' => [
|
||||||
|
'name' => 'Kategorie',
|
||||||
|
'type' => 'text',
|
||||||
|
'exampleValue' => '293',
|
||||||
|
'title' => 'Nummer des Kategorie in der URL: Der einzugebende Kategorienummer steht nach "groups=" und vor einem "&".
|
||||||
|
Beispiel: Wenn die URL der Gruppe, die im Browser angezeigt wird, :
|
||||||
|
https://www.mydealz.de/gruppe/telefon-internet?groups=153%2C154&sortBy=new&time_frame=0
|
||||||
|
Dann geben Sie ein:
|
||||||
|
153%2C154',
|
||||||
|
],
|
||||||
'order' => [
|
'order' => [
|
||||||
'name' => 'sortieren nach',
|
'name' => 'sortieren nach',
|
||||||
'type' => 'list',
|
'type' => 'list',
|
||||||
@ -84,6 +94,7 @@ dsl',
|
|||||||
'uri-group' => 'gruppe/',
|
'uri-group' => 'gruppe/',
|
||||||
'uri-deal' => 'deals/',
|
'uri-deal' => 'deals/',
|
||||||
'uri-merchant' => 'search/gutscheine?merchant-id=',
|
'uri-merchant' => 'search/gutscheine?merchant-id=',
|
||||||
|
'image-host' => 'https://static.mydealz.de/',
|
||||||
'request-error' => 'Could not request mydeals',
|
'request-error' => 'Could not request mydeals',
|
||||||
'thread-error' => 'Die ID der Diskussion kann nicht ermittelt werden. Überprüfen Sie die eingegebene URL',
|
'thread-error' => 'Die ID der Diskussion kann nicht ermittelt werden. Überprüfen Sie die eingegebene URL',
|
||||||
'currency' => '€',
|
'currency' => '€',
|
||||||
|
@ -6,7 +6,7 @@ class NurembergerNachrichtenBridge extends BridgeAbstract
|
|||||||
const NAME = 'Nürnberger Nachrichten';
|
const NAME = 'Nürnberger Nachrichten';
|
||||||
const CACHE_TIMEOUT = 3600;
|
const CACHE_TIMEOUT = 3600;
|
||||||
const URI = 'https://www.nn.de';
|
const URI = 'https://www.nn.de';
|
||||||
const DESCRIPTION = 'Bridge for Bavarian regional news site nordbayern.de';
|
const DESCRIPTION = 'Bridge for NurembergerNachrichten news site nn.de';
|
||||||
const PARAMETERS = [ [
|
const PARAMETERS = [ [
|
||||||
'region' => [
|
'region' => [
|
||||||
'name' => 'region',
|
'name' => 'region',
|
||||||
@ -66,7 +66,7 @@ class NurembergerNachrichtenBridge extends BridgeAbstract
|
|||||||
// exclude nn+ articles if desired
|
// exclude nn+ articles if desired
|
||||||
if (
|
if (
|
||||||
$this->getInput('hideNNPlus') &&
|
$this->getInput('hideNNPlus') &&
|
||||||
str_contains($articleContent->find('article[id=article]', 0)->find('header', 0), 'icon-nnplus')
|
$articleContent->find('div[class=paywall]')
|
||||||
) {
|
) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
54
bridges/OSVBridge.php
Executable file
54
bridges/OSVBridge.php
Executable file
@ -0,0 +1,54 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class OSVBridge extends BridgeAbstract
|
||||||
|
{
|
||||||
|
const NAME = 'OSV';
|
||||||
|
const DESCRIPTION = 'Parse osv.dev vulns';
|
||||||
|
const MAINTAINER = 'void';
|
||||||
|
const URI = "https://osv.dev/list";
|
||||||
|
const MAIN_DOMAIN = "https://osv.dev";
|
||||||
|
|
||||||
|
const PARAMETERS = [[
|
||||||
|
]];
|
||||||
|
|
||||||
|
protected function parseItems($html) {
|
||||||
|
foreach ($html->find('.vuln-table-row') as $element) {
|
||||||
|
$item = [];
|
||||||
|
$link = $element->find('.vuln-table-cell > a', 0);
|
||||||
|
if (empty($link)) continue;
|
||||||
|
$time = $element->find('span.vuln-table-cell',3)->find('relative-time',0);
|
||||||
|
$summary = $element->find('.vuln-summary',0);
|
||||||
|
$tags = $element->find('ul.tags > li',0);
|
||||||
|
|
||||||
|
$item['uri'] = self::MAIN_DOMAIN . $link->href;
|
||||||
|
$item['title'] = $link->innertext;
|
||||||
|
$item['title'] .= sprintf(" - %s", trim($summary->innertext));
|
||||||
|
|
||||||
|
$item['timestamp'] = $time->datetime;
|
||||||
|
$packages = "";
|
||||||
|
foreach ($element->find('ul.packages > li',0) as $pack) {
|
||||||
|
$packages .= !empty($pack->innertext) ? "<li>$pack->innertext</li>" : "";
|
||||||
|
}
|
||||||
|
$tagsout = "";
|
||||||
|
foreach ($element->find('ul.tags > li > span') as $tag) {
|
||||||
|
$tagsout .= !empty($tag->innertext) ? "<li>{$tag->innertext}</li>" : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
$item['content'] = "{$link->innertext} - {$summary->innertext}<br/>Published: {$time->innertext}<br/>Packages: <ul>{$packages}</ul><br/>Tags: <ul>{$tagsout}</ul>";
|
||||||
|
$item['uid'] = $link->innertext;
|
||||||
|
|
||||||
|
$this->items[] = $item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public function collectData()
|
||||||
|
{
|
||||||
|
$html = getSimpleHTMLDOM($this->getURI());
|
||||||
|
$this->parseItems($html);
|
||||||
|
usort($this->items, function($a, $b) {
|
||||||
|
if ($a['timestamp'] == $b['timestamp']) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return ($a['timestamp'] > $b['timestamp']) ? -1 : 1;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -62,7 +62,7 @@ class PepperBridgeAbstract extends BridgeAbstract
|
|||||||
foreach ($list as $deal) {
|
foreach ($list as $deal) {
|
||||||
// Get the JSON Data stored as vue
|
// Get the JSON Data stored as vue
|
||||||
$jsonDealData = $this->getDealJsonData($deal);
|
$jsonDealData = $this->getDealJsonData($deal);
|
||||||
$dealMeta = Json::decode($deal->find('div[class=threadGrid-headerMeta]', 0)->find('div[class=js-vue2]', 1)->getAttribute('data-vue2'));
|
$dealMeta = Json::decode($deal->find('div[class=js-vue2]', 1)->getAttribute('data-vue2'));
|
||||||
|
|
||||||
$item = [];
|
$item = [];
|
||||||
$item['uri'] = $this->getDealURI($jsonDealData);
|
$item['uri'] = $this->getDealURI($jsonDealData);
|
||||||
@ -80,7 +80,7 @@ class PepperBridgeAbstract extends BridgeAbstract
|
|||||||
. $this->getShipsFrom($dealMeta)
|
. $this->getShipsFrom($dealMeta)
|
||||||
. $this->getShippingCost($jsonDealData)
|
. $this->getShippingCost($jsonDealData)
|
||||||
. $this->getSource($jsonDealData)
|
. $this->getSource($jsonDealData)
|
||||||
. $this->getDealLocation($dealMeta)
|
. $this->getDealLocation($jsonDealData)
|
||||||
. $deal->find('div[class*=' . $selectorDescription . ']', 0)->innertext
|
. $deal->find('div[class*=' . $selectorDescription . ']', 0)->innertext
|
||||||
. '</td><td>'
|
. '</td><td>'
|
||||||
. $this->getTemperature($jsonDealData)
|
. $this->getTemperature($jsonDealData)
|
||||||
@ -402,14 +402,9 @@ HEREDOC;
|
|||||||
* Get the Deal location if it exists
|
* Get the Deal location if it exists
|
||||||
* @return string String of the deal location
|
* @return string String of the deal location
|
||||||
*/
|
*/
|
||||||
private function getDealLocation($dealMeta)
|
private function getDealLocation($jsonDealData)
|
||||||
{
|
{
|
||||||
$ribbons = $dealMeta['props']['metaRibbons'];
|
if ($jsonDealData['props']['thread']['isLocal']) {
|
||||||
$isLocal = false;
|
|
||||||
foreach ($ribbons as $ribbon) {
|
|
||||||
$isLocal |= ($ribbon['type'] == 'local');
|
|
||||||
}
|
|
||||||
if ($isLocal) {
|
|
||||||
$content = '<div>' . $this->i8n('deal-type') . ' : ' . $this->i8n('localdeal') . '</div>';
|
$content = '<div>' . $this->i8n('deal-type') . ' : ' . $this->i8n('localdeal') . '</div>';
|
||||||
} else {
|
} else {
|
||||||
$content = '';
|
$content = '';
|
||||||
@ -424,8 +419,11 @@ HEREDOC;
|
|||||||
private function getImage($deal)
|
private function getImage($deal)
|
||||||
{
|
{
|
||||||
// Get thread Image JSON content
|
// Get thread Image JSON content
|
||||||
$content = Json::decode($deal->find('div[class*=threadGrid-image]', 0)->find('div[class=js-vue2]', 0)->getAttribute('data-vue2'));
|
$content = Json::decode($deal->find('div[class=js-vue2]', 0)->getAttribute('data-vue2'));
|
||||||
return '<img src="' . $content['props']['threadImageUrl'] . '"/>';
|
//return '<img src="' . $content['props']['threadImageUrl'] . '"/>';
|
||||||
|
return '<img src="' . $this->i8n('image-host') . $content['props']['thread']['mainImage']['path'] . '/'
|
||||||
|
. $content['props']['thread']['mainImage']['name'] . '/re/202x202/qt/70/'
|
||||||
|
. $content['props']['thread']['mainImage']['uid'] . '"/>';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -434,7 +432,7 @@ HEREDOC;
|
|||||||
*/
|
*/
|
||||||
private function getShipsFrom($dealMeta)
|
private function getShipsFrom($dealMeta)
|
||||||
{
|
{
|
||||||
$metas = $dealMeta['props']['metaRibbons'];
|
$metas = $dealMeta['props']['metaRibbons'] ?? [];
|
||||||
$shipsFrom = null;
|
$shipsFrom = null;
|
||||||
foreach ($metas as $meta) {
|
foreach ($metas as $meta) {
|
||||||
if ($meta['type'] == 'dispatched-from') {
|
if ($meta['type'] == 'dispatched-from') {
|
||||||
@ -524,6 +522,7 @@ HEREDOC;
|
|||||||
{
|
{
|
||||||
$group = $this->getInput('group');
|
$group = $this->getInput('group');
|
||||||
$order = $this->getInput('order');
|
$order = $this->getInput('order');
|
||||||
|
$subgroups = $this->getInput('subgroups');
|
||||||
|
|
||||||
// This permit to keep the existing Feed to work
|
// This permit to keep the existing Feed to work
|
||||||
if ($order == $this->i8n('context-hot')) {
|
if ($order == $this->i8n('context-hot')) {
|
||||||
@ -533,7 +532,7 @@ HEREDOC;
|
|||||||
}
|
}
|
||||||
|
|
||||||
$url = $this->i8n('bridge-uri')
|
$url = $this->i8n('bridge-uri')
|
||||||
. $this->i8n('uri-group') . $group . '?sortBy=' . $sortBy;
|
. $this->i8n('uri-group') . $group . '?sortBy=' . $sortBy . '&groups=' . $subgroups;
|
||||||
return $url;
|
return $url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ class RadioMelodieBridge extends BridgeAbstract
|
|||||||
$picture = [];
|
$picture = [];
|
||||||
|
|
||||||
// Get the Main picture URL
|
// Get the Main picture URL
|
||||||
$picture[] = self::URI . $article->find('figure[class*=photoviewer]', 0)->find('img', 0)->src;
|
$picture[] = $article->find('figure[class*=photoviewer]', 0)->find('img', 0)->src;
|
||||||
$audioHTML = $article->find('audio');
|
$audioHTML = $article->find('audio');
|
||||||
|
|
||||||
// Add the audio element to the enclosure
|
// Add the audio element to the enclosure
|
||||||
@ -123,7 +123,7 @@ class RadioMelodieBridge extends BridgeAbstract
|
|||||||
preg_match('/wavesurfer[0-9]+.load\(\'(.*)\'\)/m', $js->innertext, $urls);
|
preg_match('/wavesurfer[0-9]+.load\(\'(.*)\'\)/m', $js->innertext, $urls);
|
||||||
|
|
||||||
// Create the plain HTML <audio> content to play this audio file
|
// Create the plain HTML <audio> content to play this audio file
|
||||||
$content = '<audio style="width: 100%" src="' . $urls[1] . '" controls ></audio>';
|
$content = '<audio style="width: 100%" src="' . self::URI . $urls[1] . '" controls ></audio>';
|
||||||
|
|
||||||
// Replace the <script> tag by the <audio> tag
|
// Replace the <script> tag by the <audio> tag
|
||||||
$js->outertext = $content;
|
$js->outertext = $content;
|
||||||
|
@ -35,7 +35,7 @@ class ReutersBridge extends BridgeAbstract
|
|||||||
'title' => 'Feeds from Reuters U.S/International edition',
|
'title' => 'Feeds from Reuters U.S/International edition',
|
||||||
'values' => [
|
'values' => [
|
||||||
'Top News' => 'home/topnews',
|
'Top News' => 'home/topnews',
|
||||||
'Fact Check' => 'chan:abtpk0vm',
|
'Fact Check' => '/fact-check',
|
||||||
'Entertainment' => 'chan:8ym8q8dl',
|
'Entertainment' => 'chan:8ym8q8dl',
|
||||||
'Politics' => 'politics',
|
'Politics' => 'politics',
|
||||||
'Wire' => 'wire',
|
'Wire' => 'wire',
|
||||||
@ -137,7 +137,6 @@ class ReutersBridge extends BridgeAbstract
|
|||||||
|
|
||||||
const OLD_WIRE_SECTION = [
|
const OLD_WIRE_SECTION = [
|
||||||
'home/topnews',
|
'home/topnews',
|
||||||
'chan:abtpk0vm',
|
|
||||||
'chan:8ym8q8dl',
|
'chan:8ym8q8dl',
|
||||||
'politics',
|
'politics',
|
||||||
'wire'
|
'wire'
|
||||||
|
100
bridges/ShadertoyBridge.php
Normal file
100
bridges/ShadertoyBridge.php
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class ShadertoyBridge extends BridgeAbstract
|
||||||
|
{
|
||||||
|
const NAME = 'Shadertoy';
|
||||||
|
const URI = 'https://www.shadertoy.com';
|
||||||
|
const DESCRIPTION = 'Latest submissions on Shadertoy';
|
||||||
|
const MAINTAINER = 'thefranke';
|
||||||
|
const CACHE_TIMEOUT = 3600; // 1h
|
||||||
|
const PARAMETERS = [
|
||||||
|
[
|
||||||
|
'category' => [
|
||||||
|
'name' => 'category',
|
||||||
|
'type' => 'list',
|
||||||
|
'exampleValue' => 'Popular',
|
||||||
|
'title' => 'Select a category',
|
||||||
|
'values' => [
|
||||||
|
'Shaders of the Week' => 'sotw',
|
||||||
|
'Popular' => 'popular',
|
||||||
|
'Newest' => 'newest',
|
||||||
|
'Hot' => 'hot',
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
public function postprocessDescription($content)
|
||||||
|
{
|
||||||
|
// replace [url] tags
|
||||||
|
$pattern = '/\[\/?url.*?\]/';
|
||||||
|
$replace = '';
|
||||||
|
$content = preg_replace($pattern, $replace, $content);
|
||||||
|
|
||||||
|
// find URLs and turn then into hyperlinks
|
||||||
|
$pattern = '/(http|https|ftp|ftps)\:\/\/[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(\/\S*)?/';
|
||||||
|
$replace = '<a href="$0">$0</a>';
|
||||||
|
$content = preg_replace($pattern, $replace, $content);
|
||||||
|
|
||||||
|
return $content;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function collectData()
|
||||||
|
{
|
||||||
|
$category = $this->getInput('category');
|
||||||
|
$json = null;
|
||||||
|
|
||||||
|
if ($category == 'sotw') {
|
||||||
|
$url = static::URI . '/playlist/week';
|
||||||
|
$contents = getContents($url);
|
||||||
|
$shaderids = extractFromDelimiters($contents, 'var gShaderIDs = ', ';');
|
||||||
|
$shaderids = str_replace('\'', '"', $shaderids);
|
||||||
|
|
||||||
|
$url = static::URI . '/shadertoy';
|
||||||
|
$data = 's=' . rawurlencode('{ "shaders": ' . $shaderids . ' }') . '&nt=0&nl=0&np=0';
|
||||||
|
$header = [
|
||||||
|
'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:135.0) Gecko/20100101 Firefox/135.0',
|
||||||
|
'Content-Type: application/x-www-form-urlencoded',
|
||||||
|
'Accept: */*',
|
||||||
|
'Origin: https://www.shadertoy.com',
|
||||||
|
'Referer: https://www.shadertoy.com/playlist/week',
|
||||||
|
];
|
||||||
|
|
||||||
|
$opts = [
|
||||||
|
CURLOPT_POST => true,
|
||||||
|
CURLOPT_POSTFIELDS => $data,
|
||||||
|
CURLOPT_RETURNTRANSFER => true
|
||||||
|
];
|
||||||
|
$json = getContents($url, $header, $opts);
|
||||||
|
} else {
|
||||||
|
$url = static::URI . '/results?sort=' . $category;
|
||||||
|
$contents = getContents($url);
|
||||||
|
$json = extractFromDelimiters($contents, 'var gShaders=', 'var gUseScreenshots');
|
||||||
|
$json = substr(trim($json), 0, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
$json = Json::decode($json);
|
||||||
|
|
||||||
|
if (!$json) {
|
||||||
|
throw new Exception(sprintf('Unable to find css selector on `%s`', static::URI));
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($json as $article) {
|
||||||
|
$id = $article['info']['id'];
|
||||||
|
|
||||||
|
$title = $article['info']['name'];
|
||||||
|
$author = $article['info']['username'];
|
||||||
|
$uri = static::URI . '/view/' . $id;
|
||||||
|
$content = '<p><img src="' . static::URI . '/media/shaders/' . $id . '.jpg"></p><p>' . $this->postprocessDescription($article['info']['description']) . '</p>';
|
||||||
|
$timestamp = $article['info']['date'];
|
||||||
|
|
||||||
|
$this->items[] = [
|
||||||
|
'title' => $title,
|
||||||
|
'author' => $author,
|
||||||
|
'uri' => $uri,
|
||||||
|
'content' => $content,
|
||||||
|
'timestamp' => $timestamp,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -57,6 +57,9 @@ class TldrTechBridge extends BridgeAbstract
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$itemUrl = Url::fromString(self::URI . ltrim($child->href, '/'));
|
$itemUrl = Url::fromString(self::URI . ltrim($child->href, '/'));
|
||||||
|
if ($itemUrl == $locationUrl) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
$this->extractItem($itemUrl);
|
$this->extractItem($itemUrl);
|
||||||
if (count($this->items) >= $limit) {
|
if (count($this->items) >= $limit) {
|
||||||
break;
|
break;
|
||||||
@ -125,6 +128,11 @@ class TldrTechBridge extends BridgeAbstract
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
foreach ($content->find('section') as $section) {
|
||||||
|
if (count($section->children()) == 0) {
|
||||||
|
$content->removeChild($section);
|
||||||
|
}
|
||||||
|
}
|
||||||
$title = $content->find('h2', 0);
|
$title = $content->find('h2', 0);
|
||||||
return [$content->innertext, $title->plaintext];
|
return [$content->innertext, $title->plaintext];
|
||||||
}
|
}
|
||||||
|
28
bridges/TomsToucheBridge.php
Normal file
28
bridges/TomsToucheBridge.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class TomsToucheBridge extends BridgeAbstract
|
||||||
|
{
|
||||||
|
const NAME = 'Toms Touché';
|
||||||
|
const URI = 'https://taz.de/#!tom=tomdestages';
|
||||||
|
const DESCRIPTION = 'Your daily dose of Toms Touche.';
|
||||||
|
const MAINTAINER = 'latz';
|
||||||
|
const CACHE_TIMEOUT = 3600; // 1h
|
||||||
|
|
||||||
|
public function collectData()
|
||||||
|
{
|
||||||
|
$url = 'https://taz.de/';
|
||||||
|
$html = getSimpleHTMLDOM($url); // Docs: https://simplehtmldom.sourceforge.io/docs/1.9/index.html
|
||||||
|
$date = $html->find('p[x-ref]');
|
||||||
|
$date = trim($date[0]->innertext);
|
||||||
|
[$day, $month, $year] = explode('.', $date);
|
||||||
|
$image = $html->find('img[alt="tom des tages"]');
|
||||||
|
|
||||||
|
$item = [];
|
||||||
|
$item['title'] = "Toms Touché - $date";
|
||||||
|
$item['uri'] = 'https://taz.de/#!tom=tomdestages';
|
||||||
|
$item['timestamp'] = mktime(0, 0, 0, $month, $day, $year);
|
||||||
|
$item['content'] = $image[0] . '</img>'; // This isn't good HTML style, but at least syntactically correct
|
||||||
|
$item['uid'] = $image[0]->getAttribute('src');
|
||||||
|
$this->items[] = $item;
|
||||||
|
}
|
||||||
|
}
|
@ -7,8 +7,8 @@ class VkBridge extends BridgeAbstract
|
|||||||
// const MAINTAINER = 'ahiles3005';
|
// const MAINTAINER = 'ahiles3005';
|
||||||
const NAME = 'VK.com';
|
const NAME = 'VK.com';
|
||||||
const URI = 'https://vk.com/';
|
const URI = 'https://vk.com/';
|
||||||
const CACHE_TIMEOUT = 300; // 5min
|
const CACHE_TIMEOUT = 3600; // 1h
|
||||||
const DESCRIPTION = 'Working with open pages';
|
const DESCRIPTION = 'Does not work anymore';
|
||||||
const PARAMETERS = [
|
const PARAMETERS = [
|
||||||
[
|
[
|
||||||
'u' => [
|
'u' => [
|
||||||
@ -65,6 +65,7 @@ class VkBridge extends BridgeAbstract
|
|||||||
|
|
||||||
public function collectData()
|
public function collectData()
|
||||||
{
|
{
|
||||||
|
return;
|
||||||
$text_html = $this->getContents();
|
$text_html = $this->getContents();
|
||||||
|
|
||||||
$text_html = iconv('windows-1251', 'utf-8//ignore', $text_html);
|
$text_html = iconv('windows-1251', 'utf-8//ignore', $text_html);
|
||||||
@ -391,10 +392,13 @@ class VkBridge extends BridgeAbstract
|
|||||||
$item['categories'] = $hashtags;
|
$item['categories'] = $hashtags;
|
||||||
|
|
||||||
// get post link
|
// get post link
|
||||||
$post_link = $post->find('a.PostHeaderSubtitle__link', 0)->getAttribute('href');
|
$var = $post->find('a.PostHeaderSubtitle__link', 0);
|
||||||
|
if ($var) {
|
||||||
|
$post_link = $var->getAttribute('href');
|
||||||
preg_match('/wall-?\d+_(\d+)/', $post_link, $preg_match_result);
|
preg_match('/wall-?\d+_(\d+)/', $post_link, $preg_match_result);
|
||||||
$item['post_id'] = intval($preg_match_result[1]);
|
$item['post_id'] = intval($preg_match_result[1]);
|
||||||
$item['uri'] = $post_link;
|
$item['uri'] = $post_link;
|
||||||
|
}
|
||||||
$item['timestamp'] = $this->getTime($post);
|
$item['timestamp'] = $this->getTime($post);
|
||||||
$item['title'] = $this->getTitle($item['content']);
|
$item['title'] = $this->getTitle($item['content']);
|
||||||
$item['author'] = $post_author;
|
$item['author'] = $post_author;
|
||||||
@ -402,7 +406,7 @@ class VkBridge extends BridgeAbstract
|
|||||||
// do not append it now
|
// do not append it now
|
||||||
$pinned_post_item = $item;
|
$pinned_post_item = $item;
|
||||||
} else {
|
} else {
|
||||||
$last_post_id = $item['post_id'];
|
$last_post_id = $item['post_id'] ?? null;
|
||||||
$this->items[] = $item;
|
$this->items[] = $item;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -474,7 +478,10 @@ class VkBridge extends BridgeAbstract
|
|||||||
if ($accurateDateElement) {
|
if ($accurateDateElement) {
|
||||||
return $accurateDateElement->getAttribute('time');
|
return $accurateDateElement->getAttribute('time');
|
||||||
} else {
|
} else {
|
||||||
$strdate = $post->find('time.PostHeaderSubtitle__item', 0)->plaintext;
|
$strdate = $post->find('time.PostHeaderSubtitle__item', 0)->plaintext ?? null;
|
||||||
|
if (!$strdate) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
$strdate = preg_replace('/[\x00-\x1F\x7F-\xFF]/', ' ', $strdate);
|
$strdate = preg_replace('/[\x00-\x1F\x7F-\xFF]/', ' ', $strdate);
|
||||||
|
|
||||||
$date = date_parse($strdate);
|
$date = date_parse($strdate);
|
||||||
|
86
bridges/YouTubeFeedExpanderBridge.php
Normal file
86
bridges/YouTubeFeedExpanderBridge.php
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class YouTubeFeedExpanderBridge extends FeedExpander
|
||||||
|
{
|
||||||
|
const NAME = 'YouTube Feed Expander';
|
||||||
|
const MAINTAINER = 'phantop';
|
||||||
|
const URI = 'https://www.youtube.com/';
|
||||||
|
const DESCRIPTION = 'Returns the latest videos from a YouTube channel';
|
||||||
|
const PARAMETERS = [[
|
||||||
|
'channel' => [
|
||||||
|
'name' => 'Channel ID',
|
||||||
|
'required' => true,
|
||||||
|
// Example: vinesauce
|
||||||
|
'exampleValue' => 'UCzORJV8l3FWY4cFO8ot-F2w',
|
||||||
|
],
|
||||||
|
'embed' => [
|
||||||
|
'name' => 'Add embed to entry',
|
||||||
|
'type' => 'checkbox',
|
||||||
|
'required' => false,
|
||||||
|
'title' => 'Add embed to entry',
|
||||||
|
'defaultValue' => 'checked',
|
||||||
|
],
|
||||||
|
'embedurl' => [
|
||||||
|
'name' => 'Use embed page as entry url',
|
||||||
|
'type' => 'checkbox',
|
||||||
|
'required' => false,
|
||||||
|
'title' => 'Use embed page as entry url',
|
||||||
|
],
|
||||||
|
'nocookie' => [
|
||||||
|
'name' => 'Use nocookie embed page',
|
||||||
|
'type' => 'checkbox',
|
||||||
|
'required' => false,
|
||||||
|
'title' => 'Use nocookie embed page'
|
||||||
|
],
|
||||||
|
]];
|
||||||
|
|
||||||
|
public function getIcon()
|
||||||
|
{
|
||||||
|
if ($this->getInput('channel') != null) {
|
||||||
|
$html = getSimpleHTMLDOMCached($this->getURI());
|
||||||
|
$scriptRegex = '/var ytInitialData = (.*?);<\/script>/';
|
||||||
|
$result = preg_match($scriptRegex, $html, $matches);
|
||||||
|
if (isset($matches[1])) {
|
||||||
|
$json = json_decode($matches[1]);
|
||||||
|
return $json->metadata->channelMetadataRenderer->avatar->thumbnails[0]->url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return parent::getIcon();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function collectData()
|
||||||
|
{
|
||||||
|
$url = 'https://www.youtube.com/feeds/videos.xml?channel_id=' . $this->getInput('channel');
|
||||||
|
$this->collectExpandableDatas($url);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function parseItem(array $item)
|
||||||
|
{
|
||||||
|
$id = $item['yt']['videoId'];
|
||||||
|
$item['comments'] = $item['uri'] . '#comments';
|
||||||
|
$item['uid'] = $item['id'];
|
||||||
|
|
||||||
|
$thumbnail = sprintf('https://img.youtube.com/vi/%s/maxresdefault.jpg', $id);
|
||||||
|
$item['enclosures'] = [$thumbnail];
|
||||||
|
|
||||||
|
$item['content'] = $item['media']['group']['description'];
|
||||||
|
$item['content'] = str_replace("\n", '<br>', $item['content']);
|
||||||
|
unset($item['media']);
|
||||||
|
|
||||||
|
$embedURI = self::URI;
|
||||||
|
if ($this->getInput('nocookie')) {
|
||||||
|
$embedURI = 'https://www.youtube-nocookie.com/';
|
||||||
|
}
|
||||||
|
$embed = $embedURI . 'embed/' . $id;
|
||||||
|
if ($this->getInput('embed')) {
|
||||||
|
$iframe_fmt = '<iframe width="448" height="350" src="%s" title="%s" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>'; //phpcs:ignore
|
||||||
|
$iframe = sprintf($iframe_fmt, $embed, $item['title']) . '<br>';
|
||||||
|
$item['content'] = $iframe . $item['content'];
|
||||||
|
}
|
||||||
|
if ($this->getInput('embedurl')) {
|
||||||
|
$item['uri'] = $embed;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $item;
|
||||||
|
}
|
||||||
|
}
|
@ -75,7 +75,7 @@ custom_timeout = false
|
|||||||
; "" = Disabled (default)
|
; "" = Disabled (default)
|
||||||
email = ""
|
email = ""
|
||||||
|
|
||||||
; Advertise a contact Telegram url e.g. "https://t.me/elegantobjects"
|
; Advertise a contact URL (can be any URL!) e.g. "https://t.me/elegantobjects"
|
||||||
telegram = ""
|
telegram = ""
|
||||||
|
|
||||||
; Show Donation information for bridges if available.
|
; Show Donation information for bridges if available.
|
||||||
|
@ -327,7 +327,7 @@ abstract class BridgeAbstract
|
|||||||
return $this->cache->get($this->getShortName() . '_' . $key, $default);
|
return $this->cache->get($this->getShortName() . '_' . $key, $default);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function saveCacheValue(string $key, $value, int $ttl = null)
|
protected function saveCacheValue(string $key, $value, int $ttl = 86400)
|
||||||
{
|
{
|
||||||
$this->cache->set($this->getShortName() . '_' . $key, $value, $ttl);
|
$this->cache->set($this->getShortName() . '_' . $key, $value, $ttl);
|
||||||
}
|
}
|
||||||
|
@ -177,11 +177,9 @@ function getSimpleHTMLDOM(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets contents from the Internet as simplhtmldom object. Contents are cached
|
* Fetch contents from the Internet as simplhtmldom object. Contents are cached
|
||||||
* and re-used for subsequent calls until the cache duration elapsed.
|
* and re-used for subsequent calls until the cache duration elapsed.
|
||||||
*
|
*
|
||||||
* _Notice_: Cached contents are forcefully removed after 24 hours (86400 seconds).
|
|
||||||
*
|
|
||||||
* @param string $url The URL.
|
* @param string $url The URL.
|
||||||
* @param int $ttl Cache duration in seconds.
|
* @param int $ttl Cache duration in seconds.
|
||||||
* @param array $header (optional) A list of cURL header.
|
* @param array $header (optional) A list of cURL header.
|
||||||
|
@ -52,7 +52,7 @@
|
|||||||
|
|
||||||
<?php if ($admin_telegram): ?>
|
<?php if ($admin_telegram): ?>
|
||||||
<div>
|
<div>
|
||||||
Telegram: <a href="<?= e($admin_telegram) ?>"><?= e($admin_telegram) ?></a>
|
Url: <a href="<?= e($admin_telegram) ?>"><?= e($admin_telegram) ?></a>
|
||||||
</div>
|
</div>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user