mirror of
https://github.com/RSS-Bridge/rss-bridge.git
synced 2025-08-26 17:44:49 +02:00
Compare commits
44 Commits
2018-03-11
...
2018-04-20
Author | SHA1 | Date | |
---|---|---|---|
|
b0c7a62f74 | ||
|
57b15a089e | ||
|
4b7fbe4188 | ||
|
2390fb58b3 | ||
|
1e8d29f6ec | ||
|
644d13686c | ||
|
aa0ff1c9b1 | ||
|
539d9f1f06 | ||
|
5ece801ce7 | ||
|
4dcea6d9c9 | ||
|
d69e2521f1 | ||
|
7927d73719 | ||
|
0620f30ae0 | ||
|
795494cfce | ||
|
ba8542156c | ||
|
55f112e034 | ||
|
208fff801d | ||
|
3c9860de43 | ||
|
a16ec196c5 | ||
|
887fc7b037 | ||
|
1bd4a40f71 | ||
|
494169f959 | ||
|
178177e787 | ||
|
1cb83ccea3 | ||
|
c899399569 | ||
|
0f93370e92 | ||
|
45c3dcb636 | ||
|
ecfc220b10 | ||
|
4b3efed7ec | ||
|
bc28c5da8e | ||
|
5bd9c1611d | ||
|
6caca4946b | ||
|
ee78e7613f | ||
|
2df2623430 | ||
|
de5f850cdb | ||
|
ac6847045c | ||
|
df6da837dc | ||
|
41b7984a4e | ||
|
38c7e0272e | ||
|
29c690dbcd | ||
|
8ba817478b | ||
|
cacbe90102 | ||
|
cb91cd5d2f | ||
|
52dfa3fe76 |
5
.gitignore
vendored
5
.gitignore
vendored
@@ -231,4 +231,7 @@ DEBUG
|
|||||||
######################
|
######################
|
||||||
## VisualStudioCode ##
|
## VisualStudioCode ##
|
||||||
######################
|
######################
|
||||||
.vscode/*
|
.vscode/*
|
||||||
|
|
||||||
|
#Builder
|
||||||
|
.buildconfig
|
||||||
|
@@ -64,13 +64,11 @@ class Arte7Bridge extends BridgeAbstract {
|
|||||||
. $lang
|
. $lang
|
||||||
. ($category != null ? '&category.code=' . $category : '');
|
. ($category != null ? '&category.code=' . $category : '');
|
||||||
|
|
||||||
$context = array(
|
$header = array(
|
||||||
'http' => array(
|
'Authorization: Bearer ' . self::API_TOKEN
|
||||||
'header' => 'Authorization: Bearer '. self::API_TOKEN
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
$input = getContents($url, false, stream_context_create($context)) or die('Could not request ARTE.');
|
$input = getContents($url, $header) or die('Could not request ARTE.');
|
||||||
$input_json = json_decode($input, true);
|
$input_json = json_decode($input, true);
|
||||||
|
|
||||||
foreach($input_json['videos'] as $element) {
|
foreach($input_json['videos'] as $element) {
|
||||||
|
@@ -15,8 +15,13 @@ class DansTonChatBridge extends BridgeAbstract {
|
|||||||
foreach($html->find('div.item') as $element) {
|
foreach($html->find('div.item') as $element) {
|
||||||
$item = array();
|
$item = array();
|
||||||
$item['uri'] = $element->find('a', 0)->href;
|
$item['uri'] = $element->find('a', 0)->href;
|
||||||
$item['title'] = 'DansTonChat ' . $element->find('a', 1)->plaintext;
|
$titleContent = $element->find('h3 a', 0);
|
||||||
$item['content'] = $element->find('a', 0)->innertext;
|
if($titleContent) {
|
||||||
|
$item['title'] = 'DansTonChat ' . html_entity_decode($titleContent->plaintext, ENT_QUOTES);
|
||||||
|
} else {
|
||||||
|
$item['title'] = 'DansTonChat';
|
||||||
|
}
|
||||||
|
$item['content'] = $element->find('div.item-content a', 0)->innertext;
|
||||||
$this->items[] = $item;
|
$this->items[] = $item;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -160,9 +160,6 @@ class DealabsBridge extends BridgeAbstract {
|
|||||||
'cept-tt',
|
'cept-tt',
|
||||||
'thread-link',
|
'thread-link',
|
||||||
'linkPlain',
|
'linkPlain',
|
||||||
'space--r-1',
|
|
||||||
'size--all-s',
|
|
||||||
'size--fromW3-m',
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -208,7 +205,7 @@ class DealabsBridge extends BridgeAbstract {
|
|||||||
foreach($list as $deal) {
|
foreach($list as $deal) {
|
||||||
$item = array();
|
$item = array();
|
||||||
$item['uri'] = $deal->find('div[class=threadGrid-title]', 0)->find('a', 0)->href;
|
$item['uri'] = $deal->find('div[class=threadGrid-title]', 0)->find('a', 0)->href;
|
||||||
$item['title'] = $deal->find('a[class='. $selectorLink .']', 0
|
$item['title'] = $deal->find('a[class*='. $selectorLink .']', 0
|
||||||
)->plaintext;
|
)->plaintext;
|
||||||
$item['author'] = $deal->find('span.thread-username', 0)->plaintext;
|
$item['author'] = $deal->find('span.thread-username', 0)->plaintext;
|
||||||
$item['content'] = '<table><tr><td><a href="'
|
$item['content'] = '<table><tr><td><a href="'
|
||||||
@@ -217,9 +214,9 @@ class DealabsBridge extends BridgeAbstract {
|
|||||||
. '"><img src="'
|
. '"><img src="'
|
||||||
. $this->getImage($deal)
|
. $this->getImage($deal)
|
||||||
. '"/></td><td><h2><a href="'
|
. '"/></td><td><h2><a href="'
|
||||||
. $deal->find('a[class='. $selectorLink .']', 0)->href
|
. $deal->find('a[class*='. $selectorLink .']', 0)->href
|
||||||
. '">'
|
. '">'
|
||||||
. $deal->find('a[class='. $selectorLink .']', 0)->innertext
|
. $deal->find('a[class*='. $selectorLink .']', 0)->innertext
|
||||||
. '</a></h2>'
|
. '</a></h2>'
|
||||||
. $this->getPrix($deal)
|
. $this->getPrix($deal)
|
||||||
. $this->getReduction($deal)
|
. $this->getReduction($deal)
|
||||||
|
@@ -4,143 +4,163 @@ class DemonoidBridge extends BridgeAbstract {
|
|||||||
const MAINTAINER = 'metaMMA';
|
const MAINTAINER = 'metaMMA';
|
||||||
const NAME = 'Demonoid';
|
const NAME = 'Demonoid';
|
||||||
const URI = 'https://www.demonoid.pw/';
|
const URI = 'https://www.demonoid.pw/';
|
||||||
const DESCRIPTION = 'Returns results for the keywords (in all categories or
|
const DESCRIPTION = 'Returns results from search';
|
||||||
a specific category). You can put several keywords separated by a semicolon
|
|
||||||
(e.g. "one show;another show"). Searches can by done in a specific category;
|
|
||||||
category number must be specified. (All=0, Movies=1, Music=2, TV=3, Games=4,
|
|
||||||
Applications=5, Pictures=8, Anime=9, Comics=10, Books=11 Music Videos=8,
|
|
||||||
Audio Books=17). User feed takes the Uploader ID number (not uploader name)
|
|
||||||
as keyword. Uploader ID is found by clicking on uploader, clicking on
|
|
||||||
"View this user\'s torrents", and copying the number after "uid=". An entire
|
|
||||||
category feed is accomplished by leaving "keywords" box blank and using the
|
|
||||||
corresponding category number.';
|
|
||||||
|
|
||||||
const PARAMETERS = array( array(
|
const PARAMETERS = array(array(
|
||||||
'q' => array(
|
'q' => array(
|
||||||
'name' => 'keywords/user ID/category, separated by semicolons',
|
'name' => 'keywords',
|
||||||
'exampleValue' => 'first list;second list;…',
|
'exampleValue' => 'keyword1 keyword2…',
|
||||||
'required' => true
|
'required' => true,
|
||||||
),
|
),
|
||||||
'crit' => array(
|
'category' => array(
|
||||||
|
'name' => 'Category',
|
||||||
'type' => 'list',
|
'type' => 'list',
|
||||||
'name' => 'Feed type',
|
|
||||||
'values' => array(
|
'values' => array(
|
||||||
'search' => 'search',
|
'All' => 0,
|
||||||
'category' => 'cat',
|
'Movies' => 1,
|
||||||
'user' => 'usr'
|
'Music' => 2,
|
||||||
|
'TV' => 3,
|
||||||
|
'Games' => 4,
|
||||||
|
'Applications' => 5,
|
||||||
|
'Pictures' => 8,
|
||||||
|
'Anime' => 9,
|
||||||
|
'Comics' => 10,
|
||||||
|
'Books' => 11,
|
||||||
|
'Audiobooks' => 17
|
||||||
|
)
|
||||||
)
|
)
|
||||||
),
|
), array(
|
||||||
'catCheck' => array(
|
'catOnly' => array(
|
||||||
'type' => 'checkbox',
|
'name' => 'Category',
|
||||||
'name' => 'Specify category for keyword search ?',
|
'type' => 'list',
|
||||||
),
|
'values' => array(
|
||||||
'cat' => array(
|
'All' => 0,
|
||||||
'name' => 'Category number',
|
'Movies' => 1,
|
||||||
),
|
'Music' => 2,
|
||||||
));
|
'TV' => 3,
|
||||||
|
'Games' => 4,
|
||||||
|
'Applications' => 5,
|
||||||
|
'Pictures' => 8,
|
||||||
|
'Anime' => 9,
|
||||||
|
'Comics' => 10,
|
||||||
|
'Books' => 11,
|
||||||
|
'Audiobooks' => 17
|
||||||
|
)
|
||||||
|
)
|
||||||
|
), array(
|
||||||
|
'userid' => array(
|
||||||
|
'name' => 'user id',
|
||||||
|
'exampleValue' => '00000',
|
||||||
|
'required' => true,
|
||||||
|
'type' => 'number'
|
||||||
|
),
|
||||||
|
'category' => array(
|
||||||
|
'name' => 'Category',
|
||||||
|
'type' => 'list',
|
||||||
|
'values' => array(
|
||||||
|
'All' => 0,
|
||||||
|
'Movies' => 1,
|
||||||
|
'Music' => 2,
|
||||||
|
'TV' => 3,
|
||||||
|
'Games' => 4,
|
||||||
|
'Applications' => 5,
|
||||||
|
'Pictures' => 8,
|
||||||
|
'Anime' => 9,
|
||||||
|
'Comics' => 10,
|
||||||
|
'Books' => 11,
|
||||||
|
'Audiobooks' => 17
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
public function collectData() {
|
public function collectData() {
|
||||||
|
|
||||||
$catBool = $this->getInput('catCheck');
|
if(!empty($this->getInput('q'))) {
|
||||||
if($catBool) {
|
|
||||||
$catNum = $this->getInput('cat');
|
$html = getSimpleHTMLDOM(
|
||||||
|
self::URI .
|
||||||
|
'files/?category=' .
|
||||||
|
rawurlencode($this->getInput('category')) .
|
||||||
|
'&subcategory=All&quality=All&seeded=2&external=2&query=' .
|
||||||
|
urlencode($this->getInput('q')) .
|
||||||
|
'&uid=0&sort='
|
||||||
|
) or returnServerError('Could not request Demonoid.');
|
||||||
|
|
||||||
|
} elseif(!empty($this->getInput('catOnly'))) {
|
||||||
|
|
||||||
|
$html = getSimpleHTMLDOM(
|
||||||
|
self::URI .
|
||||||
|
'files/?uid=0&category=' .
|
||||||
|
rawurlencode($this->getInput('catOnly')) .
|
||||||
|
'&subcategory=0&language=0&seeded=2&quality=0&query=&sort='
|
||||||
|
) or returnServerError('Could not request Demonoid.');
|
||||||
|
|
||||||
|
} elseif(!empty($this->getInput('userid'))) {
|
||||||
|
|
||||||
|
$html = getSimpleHTMLDOM(
|
||||||
|
self::URI .
|
||||||
|
'files/?uid=' .
|
||||||
|
rawurlencode($this->getInput('userid')) .
|
||||||
|
'&seeded=2'
|
||||||
|
) or returnServerError('Could not request Demonoid.');
|
||||||
|
|
||||||
|
} else {
|
||||||
|
returnServerError('Invalid parameters !');
|
||||||
}
|
}
|
||||||
$critList = $this->getInput('crit');
|
|
||||||
|
|
||||||
$keywordsList = explode(';', $this->getInput('q'));
|
if(preg_match('~No torrents found~', $html)) {
|
||||||
foreach($keywordsList as $keywords) {
|
return;
|
||||||
switch($critList) {
|
}
|
||||||
case 'search':
|
|
||||||
if($catBool == false) {
|
$table = $html->find('td[class=ctable_content_no_pad]', 0);
|
||||||
$html = file_get_contents(
|
$cursorCount = 4;
|
||||||
self::URI .
|
$elementCount = 0;
|
||||||
'files/?category=0&subcategory=All&quality=All&seeded=2&external=2&query=' .
|
while($elementCount != 40) {
|
||||||
urlencode($keywords) . #not rawurlencode so space -> '+'
|
$elementCount++;
|
||||||
'&uid=0&sort='
|
$currentElement = $table->find('tr', $cursorCount);
|
||||||
) or returnServerError('Could not request Demonoid.');
|
if(preg_match('~items total~', $currentElement)) {
|
||||||
} else {
|
break;
|
||||||
$html = file_get_contents(
|
|
||||||
self::URI .
|
|
||||||
'files/?category=' .
|
|
||||||
rawurlencode($catNum) .
|
|
||||||
'&subcategory=All&quality=All&seeded=2&external=2&query=' .
|
|
||||||
urlencode($keywords) . #not rawurlencode so space -> '+'
|
|
||||||
'&uid=0&sort='
|
|
||||||
) or returnServerError('Could not request Demonoid.');
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'usr':
|
|
||||||
$html = file_get_contents(
|
|
||||||
self::URI .
|
|
||||||
'files/?uid=' .
|
|
||||||
rawurlencode($keywords) .
|
|
||||||
'&seeded=2'
|
|
||||||
) or returnServerError('Could not request Demonoid.');
|
|
||||||
break;
|
|
||||||
case 'cat':
|
|
||||||
$html = file_get_contents(
|
|
||||||
self::URI .
|
|
||||||
'files/?uid=0&category=' .
|
|
||||||
rawurlencode($keywords) .
|
|
||||||
'&subcategory=0&language=0&seeded=2&quality=0&query=&sort='
|
|
||||||
) or returnServerError('Could not request Demonoid.');
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
$item = array();
|
||||||
if(preg_match('~No torrents found~', $html)) {
|
//Do we have a date ?
|
||||||
returnServerError('No result for query ' . $keywords);
|
if(preg_match('~Added.*?(.*)~', $currentElement->plaintext, $dateStr)) {
|
||||||
}
|
|
||||||
|
|
||||||
$bigTable = explode('<!-- start torrent list -->', $html)[1];
|
|
||||||
$last50 = explode('<!-- end torrent list -->', $bigTable)[0];
|
|
||||||
$dateChunk = explode('added_today', $last50);
|
|
||||||
$item = array ();
|
|
||||||
|
|
||||||
for($block = 1;$block < count($dateChunk);$block++) {
|
|
||||||
preg_match('~(?<=>Add).*?(?=<)~', $dateChunk[$block], $dateStr);
|
|
||||||
if(preg_match('~today~', $dateStr[0])) {
|
if(preg_match('~today~', $dateStr[0])) {
|
||||||
date_default_timezone_set('UTC');
|
date_default_timezone_set('UTC');
|
||||||
$timestamp = mktime(0, 0, 0, gmdate('n'), gmdate('j'), gmdate('Y'));
|
$timestamp = mktime(0, 0, 0, gmdate('n'), gmdate('j'), gmdate('Y'));
|
||||||
} else {
|
} else {
|
||||||
preg_match('~(?<=ed on ).*\d+~', $dateStr[0], $fullDateStr);
|
preg_match('~(?<=ed on ).*\d+~', $currentElement->plaintext, $fullDateStr);
|
||||||
date_default_timezone_set('UTC');
|
date_default_timezone_set('UTC');
|
||||||
$dateObj = strptime($fullDateStr[0], '%A, %b %d, %Y');
|
$dateObj = strptime($fullDateStr[0], '%A, %b %d, %Y');
|
||||||
$timestamp = mktime(0, 0, 0, $dateObj['tm_mon'] + 1, $dateObj['tm_mday'], 1900 + $dateObj['tm_year']);
|
$timestamp = mktime(0, 0, 0, $dateObj['tm_mon'] + 1, $dateObj['tm_mday'], 1900 + $dateObj['tm_year']);
|
||||||
}
|
}
|
||||||
|
$cursorCount++;
|
||||||
$itemsChunk = explode('<!-- tstart -->', $dateChunk[$block]);
|
|
||||||
|
|
||||||
for($items = 1;$items < count($itemsChunk);$items++) {
|
|
||||||
$item = array();
|
|
||||||
$cols = explode('<td', $itemsChunk[$items]);
|
|
||||||
preg_match('~(?<=href=\"/).*?(?=\")~', $cols[1], $matches);
|
|
||||||
$item['id'] = self::URI . $matches[0];
|
|
||||||
preg_match('~(?<=href=\").*?(?=\")~', $cols[4], $matches);
|
|
||||||
$item['uri'] = $matches[0];
|
|
||||||
$item['timestamp'] = $timestamp;
|
|
||||||
preg_match('~(?<=href=\"/users/).*?(?=\")~', $cols[3], $matches);
|
|
||||||
$item['author'] = $matches[0];
|
|
||||||
preg_match('~(?<=/\">).*?(?=</a>)~', $cols[1], $matches);
|
|
||||||
$item['title'] = $matches[0];
|
|
||||||
preg_match('~(?<=green\">)\d+(?=</font>)~', $cols[8], $matches);
|
|
||||||
$item['seeders'] = $matches[0];
|
|
||||||
preg_match('~(?<=red\">)\d+(?=</font>)~', $cols[9], $matches);
|
|
||||||
$item['leechers'] = $matches[0];
|
|
||||||
preg_match('~(?<=>).*?(?=</td>)~', $cols[5], $matches);
|
|
||||||
$item['size'] = $matches[0];
|
|
||||||
$item['content'] = 'Uploaded by ' . $item['author']
|
|
||||||
. ' , Size ' . $item['size']
|
|
||||||
. '<br>seeders: '
|
|
||||||
. $item['seeders']
|
|
||||||
. ' | leechers: '
|
|
||||||
. $item['leechers']
|
|
||||||
. '<br><a href="'
|
|
||||||
. $item['id']
|
|
||||||
. '">info page</a>';
|
|
||||||
if(isset($item['title']))
|
|
||||||
$this->items[] = $item;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$content = $table->find('tr', $cursorCount)->find('a', 1);
|
||||||
|
$cursorCount++;
|
||||||
|
$torrentInfo = $table->find('tr', $cursorCount);
|
||||||
|
$item['timestamp'] = $timestamp;
|
||||||
|
$item['title'] = $content->plaintext;
|
||||||
|
$item['id'] = self::URI . $content->href;
|
||||||
|
$item['uri'] = self::URI . $content->href;
|
||||||
|
$item['author'] = $torrentInfo->find('a[class=user]', 0)->plaintext;
|
||||||
|
$item['seeders'] = $torrentInfo->find('font[class=green]', 0)->plaintext;
|
||||||
|
$item['leechers'] = $torrentInfo->find('font[class=red]', 0)->plaintext;
|
||||||
|
$item['size'] = $torrentInfo->find('td', 3)->plaintext;
|
||||||
|
$item['content'] = 'Uploaded by ' . $item['author']
|
||||||
|
. ' , Size ' . $item['size']
|
||||||
|
. '<br>seeders: '
|
||||||
|
. $item['seeders']
|
||||||
|
. ' | leechers: '
|
||||||
|
. $item['leechers']
|
||||||
|
. '<br><a href="'
|
||||||
|
. $item['id']
|
||||||
|
. '">info page</a>';
|
||||||
|
|
||||||
|
$this->items[] = $item;
|
||||||
|
|
||||||
|
$cursorCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
112
bridges/DiscogsBridge.php
Normal file
112
bridges/DiscogsBridge.php
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class DiscogsBridge extends BridgeAbstract {
|
||||||
|
|
||||||
|
const MAINTAINER = 'teromene';
|
||||||
|
const NAME = 'DiscogsBridge';
|
||||||
|
const URI = 'https://www.discogs.com/';
|
||||||
|
const DESCRIPTION = 'Returns releases from discogs';
|
||||||
|
const PARAMETERS = array(
|
||||||
|
'Artist Releases' => array(
|
||||||
|
'artistid' => array(
|
||||||
|
'name' => 'Artist ID',
|
||||||
|
'type' => 'number',
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'Label Releases' => array(
|
||||||
|
'labelid' => array(
|
||||||
|
'name' => 'Label ID',
|
||||||
|
'type' => 'number',
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'User Wantlist' => array(
|
||||||
|
'username_wantlist' => array(
|
||||||
|
'name' => 'Username',
|
||||||
|
'type' => 'text',
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'User Folder' => array(
|
||||||
|
'username_folder' => array(
|
||||||
|
'name' => 'Username',
|
||||||
|
'type' => 'text',
|
||||||
|
),
|
||||||
|
'folderid' => array(
|
||||||
|
'name' => 'Folder ID',
|
||||||
|
'type' => 'number',
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
public function collectData() {
|
||||||
|
|
||||||
|
if(!empty($this->getInput('artistid')) || !empty($this->getInput('labelid'))) {
|
||||||
|
|
||||||
|
if(!empty($this->getInput('artistid'))) {
|
||||||
|
$data = getContents("https://api.discogs.com/artists/"
|
||||||
|
. $this->getInput('artistid')
|
||||||
|
. "/releases?sort=year&sort_order=desc")
|
||||||
|
or returnServerError("Unable to query discogs !");
|
||||||
|
} elseif(!empty($this->getInput('labelid'))) {
|
||||||
|
$data = getContents("https://api.discogs.com/labels/"
|
||||||
|
. $this->getInput('labelid')
|
||||||
|
. "/releases?sort=year&sort_order=desc")
|
||||||
|
or returnServerError("Unable to query discogs !");
|
||||||
|
}
|
||||||
|
|
||||||
|
$jsonData = json_decode($data, true);
|
||||||
|
foreach($jsonData["releases"] as $release) {
|
||||||
|
|
||||||
|
$item = array();
|
||||||
|
$item["author"] = $release["artist"];
|
||||||
|
$item["title"] = $release["title"];
|
||||||
|
$item["id"] = $release["id"];
|
||||||
|
$resId = array_key_exists("main_release", $release) ? $release["main_release"] : $release["id"];
|
||||||
|
$item["uri"] = self::URI . $this->getInput('artistid') . "/release/" . $resId;
|
||||||
|
$item["timestamp"] = DateTime::createFromFormat("Y", $release["year"])->getTimestamp();
|
||||||
|
$item["content"] = $item["author"] . " - " . $item["title"];
|
||||||
|
$this->items[] = $item;
|
||||||
|
}
|
||||||
|
|
||||||
|
} elseif(!empty($this->getInput("username_wantlist")) || !empty($this->getInput("username_folder"))) {
|
||||||
|
|
||||||
|
if(!empty($this->getInput("username_wantlist"))) {
|
||||||
|
$data = getContents("https://api.discogs.com/users/"
|
||||||
|
. $this->getInput('username_wantlist')
|
||||||
|
. "/wants?sort=added&sort_order=desc")
|
||||||
|
or returnServerError("Unable to query discogs !");
|
||||||
|
$jsonData = json_decode($data, true)["wants"];
|
||||||
|
|
||||||
|
} elseif(!empty($this->getInput("username_folder"))) {
|
||||||
|
$data = getContents("https://api.discogs.com/users/"
|
||||||
|
. $this->getInput('username_folder')
|
||||||
|
. "/collection/folders/"
|
||||||
|
. $this->getInput("folderid")
|
||||||
|
."/releases?sort=added&sort_order=desc")
|
||||||
|
or returnServerError("Unable to query discogs !");
|
||||||
|
$jsonData = json_decode($data, true)["releases"];
|
||||||
|
}
|
||||||
|
foreach($jsonData as $element) {
|
||||||
|
|
||||||
|
$infos = $element["basic_information"];
|
||||||
|
$item = array();
|
||||||
|
$item["title"] = $infos["title"];
|
||||||
|
$item["author"] = $infos["artists"][0]["name"];
|
||||||
|
$item["id"] = $infos["artists"][0]["id"];
|
||||||
|
$item["uri"] = self::URI . $infos["artists"][0]["id"] . "/release/" . $infos["id"];
|
||||||
|
$item["timestamp"] = strtotime($element["date_added"]);
|
||||||
|
$item["content"] = $item["author"] . " - " . $item["title"];
|
||||||
|
$this->items[] = $item;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getURI() {
|
||||||
|
return self::URI;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getName() {
|
||||||
|
return static::NAME;
|
||||||
|
}
|
||||||
|
}
|
54
bridges/FDroidBridge.php
Normal file
54
bridges/FDroidBridge.php
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
<?php
|
||||||
|
class FDroidBridge extends BridgeAbstract {
|
||||||
|
|
||||||
|
const MAINTAINER = 'Mitsukarenai';
|
||||||
|
const NAME = 'F-Droid Bridge';
|
||||||
|
const URI = 'https://f-droid.org/';
|
||||||
|
const CACHE_TIMEOUT = 60 * 60 * 2; // 2 hours
|
||||||
|
const DESCRIPTION = 'Returns latest added/updated apps on the open-source Android apps repository F-Droid';
|
||||||
|
|
||||||
|
const PARAMETERS = array( array(
|
||||||
|
'u' => array(
|
||||||
|
'name' => 'Widget selection',
|
||||||
|
'type' => 'list',
|
||||||
|
'required' => true,
|
||||||
|
'values' => array(
|
||||||
|
'Latest added apps' => 'added',
|
||||||
|
'Latest updated apps' => 'updated'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
));
|
||||||
|
|
||||||
|
public function collectData(){
|
||||||
|
$url = self::URI;
|
||||||
|
$html = getSimpleHTMLDOM($url)
|
||||||
|
or returnServerError('Could not request F-Droid.');
|
||||||
|
|
||||||
|
// targetting the corresponding widget based on user selection
|
||||||
|
// "updated" is the 4th widget on the page, "added" is the 5th
|
||||||
|
|
||||||
|
switch($this->getInput('u')) {
|
||||||
|
case 'updated':
|
||||||
|
$html_widget = $html->find('div.sidebar-widget', 4);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$html_widget = $html->find('div.sidebar-widget', 5);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// and now extracting app info from the selected widget (and yeah turns out icons are of heterogeneous sizes)
|
||||||
|
|
||||||
|
foreach($html_widget->find('a') as $element) {
|
||||||
|
$item = array();
|
||||||
|
$item['uri'] = self::URI . $element->href;
|
||||||
|
$item['title'] = $element->find('h4', 0)->plaintext;
|
||||||
|
$item['icon'] = $element->find('img', 0)->src;
|
||||||
|
$item['summary'] = $element->find('span.package-summary', 0)->plaintext;
|
||||||
|
$item['content'] = '
|
||||||
|
<a href="'.$item['uri'].'">
|
||||||
|
<img alt="" style="max-height:128px" src="'.$item['icon'].'">
|
||||||
|
</a><br>'.$item['summary'];
|
||||||
|
$this->items[] = $item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -96,17 +96,15 @@ class FacebookBridge extends BridgeAbstract {
|
|||||||
$captcha_action = $_SESSION['captcha_action'];
|
$captcha_action = $_SESSION['captcha_action'];
|
||||||
$captcha_fields = $_SESSION['captcha_fields'];
|
$captcha_fields = $_SESSION['captcha_fields'];
|
||||||
$captcha_fields['captcha_response'] = preg_replace("/[^a-zA-Z0-9]+/", "", $_POST['captcha_response']);
|
$captcha_fields['captcha_response'] = preg_replace("/[^a-zA-Z0-9]+/", "", $_POST['captcha_response']);
|
||||||
$http_options = array(
|
|
||||||
'http' => array(
|
$header = array("Content-type:
|
||||||
'method' => 'POST',
|
application/x-www-form-urlencoded\r\nReferer: $captcha_action\r\nCookie: noscript=1\r\n");
|
||||||
'user_agent' => ini_get('user_agent'),
|
$opts = array(
|
||||||
'header' => array("Content-type:
|
CURLOPT_POST => 1,
|
||||||
application/x-www-form-urlencoded\r\nReferer: $captcha_action\r\nCookie: noscript=1\r\n"),
|
CURLOPT_POSTFIELDS => http_build_query($captcha_fields)
|
||||||
'content' => http_build_query($captcha_fields)
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
$context = stream_context_create($http_options);
|
|
||||||
$html = getContents($captcha_action, false, $context);
|
$html = getContents($captcha_action, $header, $opts);
|
||||||
|
|
||||||
if($html === false) {
|
if($html === false) {
|
||||||
returnServerError('Failed to submit captcha response back to Facebook');
|
returnServerError('Failed to submit captcha response back to Facebook');
|
||||||
@@ -120,23 +118,18 @@ class FacebookBridge extends BridgeAbstract {
|
|||||||
|
|
||||||
//Retrieve page contents
|
//Retrieve page contents
|
||||||
if(is_null($html)) {
|
if(is_null($html)) {
|
||||||
$http_options = array(
|
$header = array('Accept-Language: ' . getEnv('HTTP_ACCEPT_LANGUAGE') . "\r\n");
|
||||||
'http' => array(
|
|
||||||
'method' => 'GET',
|
// First character cannot be a forward slash
|
||||||
'user_agent' => ini_get('user_agent'),
|
if(strpos($this->getInput('u'), "/") === 0) {
|
||||||
'header' => 'Accept-Language: ' . getEnv('HTTP_ACCEPT_LANGUAGE') . "\r\n"
|
returnClientError('Remove leading slash "/" from the username!');
|
||||||
)
|
}
|
||||||
);
|
|
||||||
$context = stream_context_create($http_options);
|
|
||||||
if(!strpos($this->getInput('u'), "/")) {
|
if(!strpos($this->getInput('u'), "/")) {
|
||||||
$html = getSimpleHTMLDOM(self::URI . urlencode($this->getInput('u')) . '?_fb_noscript=1',
|
$html = getSimpleHTMLDOM(self::URI . urlencode($this->getInput('u')) . '?_fb_noscript=1', $header)
|
||||||
false,
|
|
||||||
$context)
|
|
||||||
or returnServerError('No results for this query.');
|
or returnServerError('No results for this query.');
|
||||||
} else {
|
} else {
|
||||||
$html = getSimpleHTMLDOM(self::URI . 'pages/' . $this->getInput('u') . '?_fb_noscript=1',
|
$html = getSimpleHTMLDOM(self::URI . 'pages/' . $this->getInput('u') . '?_fb_noscript=1', $header)
|
||||||
false,
|
|
||||||
$context)
|
|
||||||
or returnServerError('No results for this query.');
|
or returnServerError('No results for this query.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -3,7 +3,7 @@ class GoComicsBridge extends BridgeAbstract {
|
|||||||
|
|
||||||
const MAINTAINER = 'sky';
|
const MAINTAINER = 'sky';
|
||||||
const NAME = 'GoComics Unofficial RSS';
|
const NAME = 'GoComics Unofficial RSS';
|
||||||
const URI = 'http://www.gocomics.com/';
|
const URI = 'https://www.gocomics.com/';
|
||||||
const CACHE_TIMEOUT = 21600; // 6h
|
const CACHE_TIMEOUT = 21600; // 6h
|
||||||
const DESCRIPTION = 'The Unofficial GoComics RSS';
|
const DESCRIPTION = 'The Unofficial GoComics RSS';
|
||||||
const PARAMETERS = array( array(
|
const PARAMETERS = array( array(
|
||||||
@@ -18,25 +18,27 @@ class GoComicsBridge extends BridgeAbstract {
|
|||||||
$html = getSimpleHTMLDOM($this->getURI())
|
$html = getSimpleHTMLDOM($this->getURI())
|
||||||
or returnServerError('Could not request GoComics: ' . $this->getURI());
|
or returnServerError('Could not request GoComics: ' . $this->getURI());
|
||||||
|
|
||||||
foreach($html->find('div.comic__container') as $element) {
|
//Get info from first page
|
||||||
|
$author = preg_replace('/By /', '', $html->find(".media-subheading", 0)->plaintext);
|
||||||
|
|
||||||
$img = $element->find('.item-comic-image img', 0);
|
$link = self::URI . $html->find(".gc-deck--cta-0", 0)->find('a', 0)->href;
|
||||||
$link = $element->find('a.js-item-comic-link', 0);
|
for($i = 0; $i < 5; $i++) {
|
||||||
$comic = $img->src;
|
|
||||||
$title = $link->title;
|
|
||||||
$url = $html->find('input.js-copy-link', 0)->value;
|
|
||||||
$date = substr($title, -10);
|
|
||||||
if (empty($title))
|
|
||||||
$title = 'GoComics ' . $this->getInput('comicname') . ' on ' . $date;
|
|
||||||
$date = strtotime($date);
|
|
||||||
|
|
||||||
$item = array();
|
$item = array();
|
||||||
$item['id'] = $url;
|
|
||||||
$item['uri'] = $url;
|
$page = getSimpleHTMLDOM($link)
|
||||||
$item['title'] = $title;
|
or returnServerError('Could not request GoComics: ' . $link);
|
||||||
$item['author'] = preg_replace('/by /', '', $element->find('a.link-blended small', 0)->plaintext);
|
$imagelink = $page->find(".img-fluid", 1)->src;
|
||||||
$item['timestamp'] = $date;
|
$date = explode("/", $link);
|
||||||
$item['content'] = '<img src="' . $comic . '" alt="' . $title . '" />';
|
|
||||||
|
$item['id'] = $imagelink;
|
||||||
|
$item['uri'] = $link;
|
||||||
|
$item['author'] = $author;
|
||||||
|
$item['title'] = 'GoComics ' . $this->getInput('comicname');
|
||||||
|
$item['timestamp'] = DateTime::createFromFormat("Ymd", $date[5] . $date[6] . $date[7])->getTimestamp();
|
||||||
|
$item['content'] = '<img src="' . $imagelink . '" />';
|
||||||
|
|
||||||
|
$link = self::URI . $page->find(".js-previous-comic", 0)->href;
|
||||||
$this->items[] = $item;
|
$this->items[] = $item;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -18,8 +18,8 @@ class IPBBridge extends FeedExpander {
|
|||||||
'name' => 'Limit',
|
'name' => 'Limit',
|
||||||
'type' => 'number',
|
'type' => 'number',
|
||||||
'required' => false,
|
'required' => false,
|
||||||
'title' => 'Specify how many pages should be fetched (-1: all)',
|
'title' => 'Specifies the number of items to return on each request (-1: all)',
|
||||||
'defaultValue' => 1
|
'defaultValue' => 10
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@@ -161,15 +161,18 @@ class IPBBridge extends FeedExpander {
|
|||||||
|
|
||||||
$next = null; // Holds the URI of the next page
|
$next = null; // Holds the URI of the next page
|
||||||
|
|
||||||
do {
|
while(true) {
|
||||||
// Skip loading HTML on first iteration
|
$next = $this->$callback($html, is_null($next));
|
||||||
if(!is_null($next)) {
|
|
||||||
$html = getSimpleHTMLDOMCached($next);
|
if(is_null($next) || ($limit > 0 && count($this->items) >= $limit)) {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
$next = $this->$callback($html, is_null($next));
|
$html = getSimpleHTMLDOMCached($next);
|
||||||
$limit--;
|
}
|
||||||
} while(!is_null($next) && $limit <> 0);
|
|
||||||
|
// We might have more items than specified, remove excess
|
||||||
|
$this->items = array_slice($this->items, 0, $limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function collectTopicArticle($html, $firstrun = true){
|
private function collectTopicArticle($html, $firstrun = true){
|
||||||
|
@@ -6,23 +6,42 @@ class InstagramBridge extends BridgeAbstract {
|
|||||||
const URI = 'https://instagram.com/';
|
const URI = 'https://instagram.com/';
|
||||||
const DESCRIPTION = 'Returns the newest images';
|
const DESCRIPTION = 'Returns the newest images';
|
||||||
|
|
||||||
const PARAMETERS = array( array(
|
const PARAMETERS = array(
|
||||||
'u' => array(
|
array(
|
||||||
'name' => 'username',
|
'u' => array(
|
||||||
'required' => true
|
'name' => 'username',
|
||||||
),
|
'required' => true
|
||||||
'media_type' => array(
|
|
||||||
'name' => 'Media type',
|
|
||||||
'type' => 'list',
|
|
||||||
'required' => false,
|
|
||||||
'values' => array(
|
|
||||||
'Both' => 'all',
|
|
||||||
'Video' => 'video',
|
|
||||||
'Picture' => 'picture'
|
|
||||||
),
|
),
|
||||||
'defaultValue' => 'all'
|
'media_type' => array(
|
||||||
|
'name' => 'Media type',
|
||||||
|
'type' => 'list',
|
||||||
|
'required' => false,
|
||||||
|
'values' => array(
|
||||||
|
'Both' => 'all',
|
||||||
|
'Video' => 'video',
|
||||||
|
'Picture' => 'picture'
|
||||||
|
),
|
||||||
|
'defaultValue' => 'all'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'h' => array(
|
||||||
|
'name' => 'hashtag',
|
||||||
|
'required' => true
|
||||||
|
),
|
||||||
|
'media_type' => array(
|
||||||
|
'name' => 'Media type',
|
||||||
|
'type' => 'list',
|
||||||
|
'required' => false,
|
||||||
|
'values' => array(
|
||||||
|
'Both' => 'all',
|
||||||
|
'Video' => 'video',
|
||||||
|
'Picture' => 'picture'
|
||||||
|
),
|
||||||
|
'defaultValue' => 'all'
|
||||||
|
)
|
||||||
)
|
)
|
||||||
));
|
);
|
||||||
|
|
||||||
public function collectData(){
|
public function collectData(){
|
||||||
$html = getSimpleHTMLDOM($this->getURI())
|
$html = getSimpleHTMLDOM($this->getURI())
|
||||||
@@ -47,9 +66,14 @@ class InstagramBridge extends BridgeAbstract {
|
|||||||
$json = trim(substr($innertext, $pos + 18), ' =;');
|
$json = trim(substr($innertext, $pos + 18), ' =;');
|
||||||
$data = json_decode($json);
|
$data = json_decode($json);
|
||||||
|
|
||||||
$userMedia = $data->entry_data->ProfilePage[0]->user->media->nodes;
|
if(!is_null($this->getInput('u'))) {
|
||||||
|
$userMedia = $data->entry_data->ProfilePage[0]->graphql->user->edge_owner_to_timeline_media->edges;
|
||||||
|
} else {
|
||||||
|
$userMedia = $data->entry_data->TagPage[0]->graphql->hashtag->edge_hashtag_to_media->edges;
|
||||||
|
}
|
||||||
|
|
||||||
foreach($userMedia as $media) {
|
foreach($userMedia as $media) {
|
||||||
|
$media = $media->node;
|
||||||
// Check media type
|
// Check media type
|
||||||
switch($this->getInput('media_type')) {
|
switch($this->getInput('media_type')) {
|
||||||
case 'all': break;
|
case 'all': break;
|
||||||
@@ -63,14 +87,15 @@ class InstagramBridge extends BridgeAbstract {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$item = array();
|
$item = array();
|
||||||
$item['uri'] = self::URI . 'p/' . $media->code . '/';
|
$item['uri'] = self::URI . 'p/' . $media->shortcode . '/';
|
||||||
$item['content'] = '<img src="' . htmlentities($media->display_src) . '" />';
|
$item['content'] = '<img src="' . htmlentities($media->display_url) . '" />';
|
||||||
if (isset($media->caption)) {
|
if (isset($media->edge_media_to_caption->edges[0]->node->text)) {
|
||||||
$item['title'] = $media->caption;
|
$item['title'] = $media->edge_media_to_caption->edges[0]->node->text;
|
||||||
} else {
|
} else {
|
||||||
$item['title'] = basename($media->display_src);
|
$item['title'] = basename($media->display_url);
|
||||||
}
|
}
|
||||||
$item['timestamp'] = $media->date;
|
$item['timestamp'] = $media->taken_at_timestamp;
|
||||||
|
$item['enclosures'] = array($media->display_url);
|
||||||
$this->items[] = $item;
|
$this->items[] = $item;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -86,6 +111,8 @@ class InstagramBridge extends BridgeAbstract {
|
|||||||
public function getURI(){
|
public function getURI(){
|
||||||
if(!is_null($this->getInput('u'))) {
|
if(!is_null($this->getInput('u'))) {
|
||||||
return self::URI . urlencode($this->getInput('u'));
|
return self::URI . urlencode($this->getInput('u'));
|
||||||
|
} elseif(!is_null($this->getInput('h'))) {
|
||||||
|
return self::URI . 'explore/tags/' . urlencode($this->getInput('h'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return parent::getURI();
|
return parent::getURI();
|
||||||
|
@@ -45,9 +45,7 @@ class KernelBugTrackerBridge extends BridgeAbstract {
|
|||||||
// We use the print preview page for simplicity
|
// We use the print preview page for simplicity
|
||||||
$html = getSimpleHTMLDOMCached($this->getURI() . '&format=multiple',
|
$html = getSimpleHTMLDOMCached($this->getURI() . '&format=multiple',
|
||||||
86400,
|
86400,
|
||||||
false,
|
|
||||||
null,
|
null,
|
||||||
0,
|
|
||||||
null,
|
null,
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
|
57
bridges/NotAlwaysBridge.php
Normal file
57
bridges/NotAlwaysBridge.php
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
<?php
|
||||||
|
class NotAlwaysBridge extends BridgeAbstract {
|
||||||
|
|
||||||
|
const MAINTAINER = 'mozes';
|
||||||
|
const NAME = 'Not Always family Bridge';
|
||||||
|
const URI = 'https://notalwaysright.com/';
|
||||||
|
const DESCRIPTION = 'Returns the latest stories';
|
||||||
|
const CACHE_TIMEOUT = 1800; // 30 minutes
|
||||||
|
|
||||||
|
const PARAMETERS = array( array(
|
||||||
|
'filter' => array(
|
||||||
|
'type' => 'list',
|
||||||
|
'name' => 'Filter',
|
||||||
|
'values' => array(
|
||||||
|
'All' => 'all',
|
||||||
|
'Right' => 'right',
|
||||||
|
'Working' => 'working',
|
||||||
|
'Romantic' => 'romantic',
|
||||||
|
'Related' => 'related',
|
||||||
|
'Learning' => 'learning',
|
||||||
|
'Friendly' => 'friendly',
|
||||||
|
'Hopeless' => 'hopeless',
|
||||||
|
'Unfiltered' => 'unfiltered'
|
||||||
|
),
|
||||||
|
'required' => true
|
||||||
|
)
|
||||||
|
));
|
||||||
|
|
||||||
|
public function collectData(){
|
||||||
|
$html = getSimpleHTMLDOM($this->getURI())
|
||||||
|
or returnServerError('Could not request NotAlways.');
|
||||||
|
foreach($html->find('.post') as $post) {
|
||||||
|
#print_r($post);
|
||||||
|
$item = array();
|
||||||
|
$item['uri'] = $post->find('h1', 0)->find('a', 0)->href;
|
||||||
|
$item['content'] = $post;
|
||||||
|
$item['title'] = $post->find('h1', 0)->find('a', 0)->innertext;
|
||||||
|
$this->items[] = $item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getName(){
|
||||||
|
if(!is_null($this->getInput('filter'))) {
|
||||||
|
return $this->getInput('filter') . ' - NotAlways Bridge';
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent::getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getURI(){
|
||||||
|
if(!is_null($this->getInput('filter'))) {
|
||||||
|
return self::URI . $this->getInput('filter') . "/";
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent::getURI();
|
||||||
|
}
|
||||||
|
}
|
73
bridges/PixivBridge.php
Normal file
73
bridges/PixivBridge.php
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
<?php
|
||||||
|
class PixivBridge extends BridgeAbstract {
|
||||||
|
|
||||||
|
const MAINTAINER = 'teromene';
|
||||||
|
const NAME = 'Pixiv Bridge';
|
||||||
|
const URI = 'https://www.pixiv.net/';
|
||||||
|
const DESCRIPTION = 'Returns the tag search from pixiv.net';
|
||||||
|
|
||||||
|
|
||||||
|
const PARAMETERS = array( array(
|
||||||
|
'tag' => array(
|
||||||
|
'name' => 'Tag to search',
|
||||||
|
'exampleValue' => 'example',
|
||||||
|
'required' => true
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
|
||||||
|
public function collectData(){
|
||||||
|
|
||||||
|
$html = getContents(static::URI.'search.php?word=' . urlencode($this->getInput('tag')))
|
||||||
|
or returnClientError('Unable to query pixiv.net');
|
||||||
|
$regex = '/<input type="hidden"id="js-mount-point-search-result-list"data-items="([^"]*)/';
|
||||||
|
$timeRegex = '/img\/([0-9]{4})\/([0-9]{2})\/([0-9]{2})\/([0-9]{2})\/([0-9]{2})\/([0-9]{2})\//';
|
||||||
|
|
||||||
|
preg_match_all($regex, $html, $matches, PREG_SET_ORDER, 0);
|
||||||
|
if(!$matches) return;
|
||||||
|
|
||||||
|
$content = json_decode(html_entity_decode($matches[0][1]), true);
|
||||||
|
$count = 0;
|
||||||
|
foreach($content as $result) {
|
||||||
|
if($count == 10) break;
|
||||||
|
$count++;
|
||||||
|
|
||||||
|
$item = array();
|
||||||
|
$item["id"] = $result["illustId"];
|
||||||
|
$item["uri"] = "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=" . $result["illustId"];
|
||||||
|
$item["title"] = $result["illustTitle"];
|
||||||
|
$item["author"] = $result["userName"];
|
||||||
|
|
||||||
|
preg_match_all($timeRegex, $result["url"], $dt, PREG_SET_ORDER, 0);
|
||||||
|
$elementDate = DateTime::createFromFormat("YmdHis",
|
||||||
|
$dt[0][1] . $dt[0][2] . $dt[0][3] . $dt[0][4] . $dt[0][5] . $dt[0][6]);
|
||||||
|
$item["timestamp"] = $elementDate->getTimestamp();
|
||||||
|
|
||||||
|
$item["content"] = "<img src='" . $this->cacheImage($result['url'], $item["id"]) . "' />";
|
||||||
|
$this->items[] = $item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function cacheImage($url, $illustId) {
|
||||||
|
|
||||||
|
$url = str_replace("_master1200", "", $url);
|
||||||
|
$url = str_replace("c/240x240/img-master/", "img-original/", $url);
|
||||||
|
$path = CACHE_DIR . '/pixiv_img';
|
||||||
|
|
||||||
|
if(!is_dir($path))
|
||||||
|
mkdir($path, 0755, true);
|
||||||
|
|
||||||
|
if(!is_file($path . '/' . $illustId . '.jpeg')) {
|
||||||
|
$headers = array("Referer: https://www.pixiv.net/member_illust.php?mode=medium&illust_id=" . $illustId);
|
||||||
|
$illust = getContents($url, $headers);
|
||||||
|
if(strpos($illust, "404 Not Found") !== false) {
|
||||||
|
$illust = getContents(str_replace("jpg", "png", $url), $headers);
|
||||||
|
}
|
||||||
|
file_put_contents($path . '/' . $illustId . '.jpeg', $illust);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'cache/pixiv_img/' . $illustId . ".jpeg";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
30
bridges/RadioMelodieBridge.php
Normal file
30
bridges/RadioMelodieBridge.php
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
class RadioMelodieBridge extends BridgeAbstract {
|
||||||
|
const NAME = 'Radio Melodie Actu';
|
||||||
|
const URI = 'https://www.radiomelodie.com/';
|
||||||
|
const DESCRIPTION = 'Retourne les actualités publiées par Radio Melodie';
|
||||||
|
const MAINTAINER = 'sysadminstory';
|
||||||
|
|
||||||
|
public function collectData(){
|
||||||
|
$html = getSimpleHTMLDOM(self::URI . 'actu')
|
||||||
|
or returnServerError('Could not request Radio Melodie.');
|
||||||
|
$list = $html->find('div[class=actuitem]');
|
||||||
|
foreach($list as $element) {
|
||||||
|
$item = array();
|
||||||
|
|
||||||
|
// Get picture URL
|
||||||
|
$pictureHTML = $element->find('div[class=picture]');
|
||||||
|
preg_match(
|
||||||
|
'/background-image:url\((.*)\);/',
|
||||||
|
$pictureHTML[0]->getAttribute('style'),
|
||||||
|
$pictures);
|
||||||
|
$pictureURL = $pictures[1];
|
||||||
|
|
||||||
|
$item['enclosures'] = array($pictureURL);
|
||||||
|
$item['uri'] = self::URI . $element->parent()->href;
|
||||||
|
$item['title'] = $element->find('h3', 0)->plaintext;
|
||||||
|
$item['content'] = $element->find('p', 0)->plaintext . '<br/><img src="'.$pictureURL.'"/>';
|
||||||
|
$this->items[] = $item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -14,7 +14,7 @@ class SoundCloudBridge extends BridgeAbstract {
|
|||||||
)
|
)
|
||||||
));
|
));
|
||||||
|
|
||||||
const CLIENT_ID = '0aca19eae3843844e4053c6d8fdb7875';
|
const CLIENT_ID = '4jkoEFmZEDaqjwJ9Eih4ATNhcH3vMVfp';
|
||||||
|
|
||||||
public function collectData(){
|
public function collectData(){
|
||||||
|
|
||||||
|
@@ -4,7 +4,7 @@ class SteamBridge extends BridgeAbstract {
|
|||||||
const NAME = 'Steam Bridge';
|
const NAME = 'Steam Bridge';
|
||||||
const URI = 'https://store.steampowered.com/';
|
const URI = 'https://store.steampowered.com/';
|
||||||
const CACHE_TIMEOUT = 3600; // 1h
|
const CACHE_TIMEOUT = 3600; // 1h
|
||||||
const DESCRIPTION = 'Returns games list';
|
const DESCRIPTION = 'Returns apps list';
|
||||||
const MAINTAINER = 'jacknumber';
|
const MAINTAINER = 'jacknumber';
|
||||||
const PARAMETERS = array(
|
const PARAMETERS = array(
|
||||||
'Wishlist' => array(
|
'Wishlist' => array(
|
||||||
@@ -47,16 +47,6 @@ class SteamBridge extends BridgeAbstract {
|
|||||||
'AED' => 'ae',
|
'AED' => 'ae',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
'sort' => array(
|
|
||||||
'name' => 'Sort by',
|
|
||||||
'type' => 'list',
|
|
||||||
'values' => array(
|
|
||||||
'Rank' => 'rank',
|
|
||||||
'Date Added' => 'added',
|
|
||||||
'Name' => 'name',
|
|
||||||
'Price' => 'price',
|
|
||||||
)
|
|
||||||
),
|
|
||||||
'only_discount' => array(
|
'only_discount' => array(
|
||||||
'name' => 'Only discount',
|
'name' => 'Only discount',
|
||||||
'type' => 'checkbox',
|
'type' => 'checkbox',
|
||||||
@@ -68,49 +58,44 @@ class SteamBridge extends BridgeAbstract {
|
|||||||
|
|
||||||
$username = $this->getInput('username');
|
$username = $this->getInput('username');
|
||||||
$params = array(
|
$params = array(
|
||||||
'cc' => $this->getInput('currency'),
|
'cc' => $this->getInput('currency')
|
||||||
'sort' => $this->getInput('sort')
|
|
||||||
);
|
);
|
||||||
|
|
||||||
$url = self::URI . 'wishlist/id/' . $username . '/?' . http_build_query($params);
|
$url = self::URI . 'wishlist/id/' . $username . '?' . http_build_query($params);
|
||||||
|
|
||||||
$jsonDataRegex = '/var g_rg(?:WishlistData|AppInfo) = ([^;]*)/';
|
$targetVariable = 'g_rgAppInfo';
|
||||||
$content = getContents($url)
|
$sort = array();
|
||||||
|
|
||||||
|
$html = '';
|
||||||
|
$html = getSimpleHTMLDOM($url)
|
||||||
or returnServerError("Could not request Steam Wishlist. Tried:\n - $url");
|
or returnServerError("Could not request Steam Wishlist. Tried:\n - $url");
|
||||||
|
|
||||||
preg_match_all($jsonDataRegex, $content, $matches, PREG_SET_ORDER, 0);
|
$jsContent = $html->find('.responsive_page_template_content script', 0)->innertext;
|
||||||
|
|
||||||
$appList = json_decode($matches[0][1], true);
|
|
||||||
$fullAppList = json_decode($matches[1][1], true);
|
|
||||||
//var_dump($matches[1][1]);
|
|
||||||
//var_dump($fullAppList);
|
|
||||||
$sortedElementList = array_fill(0, count($appList), 0);
|
|
||||||
foreach($appList as $app) {
|
|
||||||
|
|
||||||
$sortedElementList[$app["priority"] - 1] = $app["appid"];
|
|
||||||
|
|
||||||
|
if(preg_match('/var ' . $targetVariable . ' = (.*?);/s', $jsContent, $matches)) {
|
||||||
|
$appsData = json_decode($matches[1]);
|
||||||
|
} else {
|
||||||
|
returnServerError("Could not parse JS variable ($targetVariable) in page content.");
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach($sortedElementList as $appId) {
|
foreach($appsData as $id => $element) {
|
||||||
|
|
||||||
$app = $fullAppList[$appId];
|
$appType = $element->type;
|
||||||
$gameTitle = $app["name"];
|
$appIsBuyable = 0;
|
||||||
$gameUri = "http://store.steampowered.com/app/" . $appId . "/";
|
$appHasDiscount = 0;
|
||||||
$gameImg = $app["capsule"];
|
$appIsFree = 0;
|
||||||
|
|
||||||
$item = array();
|
if($element->subs) {
|
||||||
$item['uri'] = $gameUri;
|
$appIsBuyable = 1;
|
||||||
$item['title'] = $gameTitle;
|
|
||||||
|
|
||||||
if(count($app["subs"]) > 0) {
|
if($element->subs[0]->discount_pct) {
|
||||||
if($app["subs"][0]["discount_pct"] != 0) {
|
|
||||||
|
|
||||||
$item['promoValue'] = $app["subs"][0]["discount_pct"];
|
$appHasDiscount = 1;
|
||||||
$item['oldPrice'] = $app["subs"][0]["price"] / 100 / ((100 - $gamePromoValue / 100));
|
$discountBlock = str_get_html($element->subs[0]->discount_block);
|
||||||
$item['newPrice'] = $app["subs"][0]["price"] / 100;
|
$appDiscountValue = $discountBlock->find('.discount_pct', 0)->plaintext;
|
||||||
$item['price'] = $item['newPrice'];
|
$appOldPrice = $discountBlock->find('.discount_original_price', 0)->plaintext;
|
||||||
|
$appNewPrice = $discountBlock->find('.discount_final_price', 0)->plaintext;
|
||||||
$item['hasPromo'] = true;
|
$appPrice = $appNewPrice;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
@@ -118,15 +103,55 @@ class SteamBridge extends BridgeAbstract {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$item['price'] = $app["subs"][0]["price"] / 100;
|
$appPrice = $element->subs[0]->price / 100;
|
||||||
$item['hasPromo'] = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if($this->getInput('only_discount')) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isset($element->free) && $element->free = 1) {
|
||||||
|
$appIsFree = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$item = array();
|
||||||
|
$item['uri'] = "http://store.steampowered.com/app/$id/";
|
||||||
|
$item['title'] = $element->name;
|
||||||
|
$item['type'] = $appType;
|
||||||
|
$item['cover'] = str_replace('_292x136', '', $element->capsule);
|
||||||
|
$item['timestamp'] = $element->added;
|
||||||
|
$item['isBuyable'] = $appIsBuyable;
|
||||||
|
$item['hasDiscount'] = $appHasDiscount;
|
||||||
|
$item['isFree'] = $appIsFree;
|
||||||
|
$item['priority'] = $element->priority;
|
||||||
|
|
||||||
|
if($appIsBuyable) {
|
||||||
|
$item['price'] = floatval(str_replace(',', '.', $appPrice));
|
||||||
|
}
|
||||||
|
|
||||||
|
if($appHasDiscount) {
|
||||||
|
|
||||||
|
$item['discount']['value'] = $appDiscountValue;
|
||||||
|
$item['discount']['oldPrice'] = floatval(str_replace(',', '.', $appOldPrice));
|
||||||
|
$item['discount']['newPrice'] = floatval(str_replace(',', '.', $appNewPrice));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->items[] = $item;
|
$item['enclosures'] = array();
|
||||||
|
$item['enclosures'][] = str_replace('_292x136', '', $element->capsule);
|
||||||
|
|
||||||
|
foreach($element->screenshots as $screenshot) {
|
||||||
|
$item['enclosures'][] = substr($element->capsule, 0, -31) . $screenshot;
|
||||||
|
}
|
||||||
|
|
||||||
|
$sort[$id] = $element->priority;
|
||||||
|
|
||||||
|
$this->items[] = $item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
array_multisort($sort, SORT_ASC, $this->items);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
57
bridges/SupInfoBridge.php
Normal file
57
bridges/SupInfoBridge.php
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
<?php
|
||||||
|
class SupInfoBridge extends BridgeAbstract {
|
||||||
|
|
||||||
|
const MAINTAINER = 'teromene';
|
||||||
|
const NAME = 'SupInfoBridge';
|
||||||
|
const URI = 'https://www.supinfo.com';
|
||||||
|
const DESCRIPTION = 'Returns the newest articles.';
|
||||||
|
|
||||||
|
const PARAMETERS = array(array(
|
||||||
|
'tag' => array(
|
||||||
|
'name' => 'Category (not mandatory)',
|
||||||
|
'type' => 'text',
|
||||||
|
)
|
||||||
|
));
|
||||||
|
|
||||||
|
public function collectData() {
|
||||||
|
|
||||||
|
if(empty($this->getInput('tag'))) {
|
||||||
|
$html = getSimpleHTMLDOM(self::URI . '/articles/')
|
||||||
|
or returnServerError('Unable to fetch articles !');
|
||||||
|
} else {
|
||||||
|
$html = getSimpleHTMLDOM(self::URI . '/articles/tag/' . $this->getInput('tag'))
|
||||||
|
or returnServerError('Unable to fetch articles !');
|
||||||
|
}
|
||||||
|
$content = $html->find('#latest', 0)->find('ul[class=courseContent]', 0);
|
||||||
|
|
||||||
|
for($i = 0; $i < 5; $i++) {
|
||||||
|
|
||||||
|
$this->items[] = $this->fetchArticle($content->find('h4', $i)->find('a', 0)->href);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function fetchArticle($link) {
|
||||||
|
|
||||||
|
$articleHTML = getSimpleHTMLDOM(self::URI . $link)
|
||||||
|
or returnServerError('Unable to fetch article !');
|
||||||
|
|
||||||
|
$article = $articleHTML->find('div[id=courseDocZero]', 0);
|
||||||
|
$item = array();
|
||||||
|
$item['author'] = $article->find('#courseMetas', 0)->find('a', 0)->plaintext;
|
||||||
|
$item['id'] = $link;
|
||||||
|
$item['uri'] = self::URI . $link;
|
||||||
|
$item['title'] = $article->find('h1', 0)->plaintext;
|
||||||
|
$date = explode(' ', $article->find('#courseMetas', 0)->find('span', 1)->plaintext);
|
||||||
|
$item['timestamp'] = DateTime::createFromFormat('d/m/Y H:i:s', $date[2] . ' ' . $date[4])->getTimestamp();
|
||||||
|
|
||||||
|
$article->find('div[id=courseHeader]', 0)->innertext = '';
|
||||||
|
$article->find('div[id=author-infos]', 0)->innertext = '';
|
||||||
|
$article->find('div[id=cartouche-tete]', 0)->innertext = '';
|
||||||
|
$item['content'] = $article;
|
||||||
|
|
||||||
|
return $item;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -1,96 +0,0 @@
|
|||||||
<?php
|
|
||||||
class T411Bridge extends BridgeAbstract {
|
|
||||||
|
|
||||||
const MAINTAINER = 'ORelio';
|
|
||||||
const NAME = 'T411 Bridge';
|
|
||||||
const URI = 'https://www.t411.al/';
|
|
||||||
const DESCRIPTION = 'Returns the 10 newest torrents with specified search
|
|
||||||
terms <br /> Use url part after "?" mark when using their search engine.';
|
|
||||||
|
|
||||||
const PARAMETERS = array( array(
|
|
||||||
'search' => array(
|
|
||||||
'name' => 'Search criteria',
|
|
||||||
'required' => true
|
|
||||||
)
|
|
||||||
));
|
|
||||||
|
|
||||||
public function collectData(){
|
|
||||||
|
|
||||||
//Utility function for retrieving text based on start and end delimiters
|
|
||||||
function extractFromDelimiters($string, $start, $end){
|
|
||||||
if(strpos($string, $start) !== false) {
|
|
||||||
$section_retrieved = substr($string, strpos($string, $start) + strlen($start));
|
|
||||||
$section_retrieved = substr($section_retrieved, 0, strpos($section_retrieved, $end));
|
|
||||||
return $section_retrieved;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Retrieve torrent listing from search results, which does not contain torrent description
|
|
||||||
$url = self::URI
|
|
||||||
. 'torrents/search/?search='
|
|
||||||
. urlencode($this->getInput('search'))
|
|
||||||
. '&order=added&type=desc';
|
|
||||||
|
|
||||||
$html = getSimpleHTMLDOM($url)
|
|
||||||
or returnServerError('Could not request t411: ' . $url);
|
|
||||||
|
|
||||||
$results = $html->find('table.results', 0);
|
|
||||||
if (is_null($results))
|
|
||||||
returnServerError('No results from t411: ' . $url);
|
|
||||||
$limit = 0;
|
|
||||||
|
|
||||||
//Process each item individually
|
|
||||||
foreach($results->find('tr') as $element) {
|
|
||||||
|
|
||||||
//Limit total amount of requests and ignore table header
|
|
||||||
if($limit >= 10) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if(is_object($element->find('th', 0))) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Requests are rate-limited
|
|
||||||
usleep(500000); //So we need to wait (500ms)
|
|
||||||
|
|
||||||
//Retrieve data from RSS entry
|
|
||||||
$item_uri = self::URI
|
|
||||||
. 'torrents/details/?id='
|
|
||||||
. extractFromDelimiters($element->find('a.nfo', 0)->outertext, '?id=', '"');
|
|
||||||
|
|
||||||
$item_title = extractFromDelimiters($element->outertext, '" title="', '"');
|
|
||||||
$item_date = strtotime($element->find('dd', 0)->plaintext);
|
|
||||||
|
|
||||||
//Retrieve full description from torrent page
|
|
||||||
$item_html = getSimpleHTMLDOM($item_uri);
|
|
||||||
if(!$item_html) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Retrieve data from page contents
|
|
||||||
$item_desc = $item_html->find('div.description', 0);
|
|
||||||
$item_author = $item_html->find('a.profile', 0)->innertext;
|
|
||||||
|
|
||||||
//Cleanup advertisments
|
|
||||||
$divs = explode('<div class="align-center">', $item_desc->innertext);
|
|
||||||
$item_desc = '';
|
|
||||||
foreach ($divs as $text)
|
|
||||||
if (strpos($text, 'adprovider.adlure.net') === false)
|
|
||||||
$item_desc = $item_desc . '<div class="align-center">' . $text;
|
|
||||||
|
|
||||||
$item_desc = preg_replace('/<h2 class="align-center">LIENS DE T..?L..?CHARGEMENT<\/h2>/i', '', $item_desc);
|
|
||||||
|
|
||||||
//Build and add final item
|
|
||||||
$item = array();
|
|
||||||
$item['uri'] = $item_uri;
|
|
||||||
$item['title'] = $item_title;
|
|
||||||
$item['author'] = $item_author;
|
|
||||||
$item['timestamp'] = $item_date;
|
|
||||||
$item['content'] = $item_desc;
|
|
||||||
$this->items[] = $item;
|
|
||||||
$limit++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -43,40 +43,225 @@ class VkBridge extends BridgeAbstract
|
|||||||
or returnServerError('No results for group or user name "' . $this->getInput('u') . '".');
|
or returnServerError('No results for group or user name "' . $this->getInput('u') . '".');
|
||||||
|
|
||||||
$text_html = iconv('windows-1251', 'utf-8', $text_html);
|
$text_html = iconv('windows-1251', 'utf-8', $text_html);
|
||||||
|
// makes album link generating work correctly
|
||||||
|
$text_html = str_replace('"class="page_album_link">', '" class="page_album_link">', $text_html);
|
||||||
$html = str_get_html($text_html);
|
$html = str_get_html($text_html);
|
||||||
$pageName = $html->find('.page_name', 0)->plaintext;
|
$pageName = $html->find('.page_name', 0);
|
||||||
$this->pageName = $pageName;
|
if (is_object($pageName)) {
|
||||||
|
$pageName = $pageName->plaintext;
|
||||||
|
$this->pageName = htmlspecialchars_decode($pageName);
|
||||||
|
}
|
||||||
|
$pinned_post_item = null;
|
||||||
|
$last_post_id = 0;
|
||||||
|
|
||||||
foreach ($html->find('.post') as $post) {
|
foreach ($html->find('.post') as $post) {
|
||||||
|
|
||||||
|
$is_pinned_post = false;
|
||||||
|
if (strpos($post->getAttribute('class'), 'post_fixed') !== false) {
|
||||||
|
$is_pinned_post = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (is_object($post->find('a.wall_post_more', 0))) {
|
if (is_object($post->find('a.wall_post_more', 0))) {
|
||||||
//delete link "show full" in content
|
//delete link "show full" in content
|
||||||
$post->find('a.wall_post_more', 0)->outertext = '';
|
$post->find('a.wall_post_more', 0)->outertext = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$content_suffix = "";
|
||||||
|
|
||||||
|
// looking for external links
|
||||||
|
$external_link_selectors = array(
|
||||||
|
'a.page_media_link_title',
|
||||||
|
'div.page_media_link_title > a',
|
||||||
|
'div.media_desc > a.lnk',
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach($external_link_selectors as $sel) {
|
||||||
|
if (is_object($post->find($sel, 0))) {
|
||||||
|
$a = $post->find($sel, 0);
|
||||||
|
$innertext = $a->innertext;
|
||||||
|
$parsed_url = parse_url($a->getAttribute('href'));
|
||||||
|
if (strpos($parsed_url['path'], '/away.php') !== 0) continue;
|
||||||
|
parse_str($parsed_url["query"], $parsed_query);
|
||||||
|
$content_suffix .= "<br>External link: <a href='" . $parsed_query["to"] . "'>$innertext</a>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove external link from content
|
||||||
|
$external_link_selectors_to_remove = array(
|
||||||
|
'div.page_media_thumbed_link',
|
||||||
|
'div.page_media_link_desc_wrap',
|
||||||
|
'div.media_desc > a.lnk',
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach($external_link_selectors_to_remove as $sel) {
|
||||||
|
if (is_object($post->find($sel, 0))) {
|
||||||
|
$post->find($sel, 0)->outertext = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// looking for article
|
||||||
|
$article = $post->find("a.article_snippet", 0);
|
||||||
|
if (is_object($article)) {
|
||||||
|
$article_title = $article->find("div.article_snippet__title", 0)->innertext;
|
||||||
|
$article_author = $article->find("div.article_snippet__author", 0)->innertext;
|
||||||
|
$article_link = self::URI . ltrim($article->getAttribute('href'), '/');
|
||||||
|
$article_img_element_style = $article->find("div.article_snippet__image", 0)->getAttribute('style');
|
||||||
|
preg_match('/background-image: url\((.*)\)/', $article_img_element_style, $matches);
|
||||||
|
if (count($matches) > 0) {
|
||||||
|
$content_suffix .= "<br><img src='" . $matches[1] . "'>";
|
||||||
|
}
|
||||||
|
$content_suffix .= "<br>Article: <a href='$article_link'>$article_title ($article_author)</a>";
|
||||||
|
$article->outertext = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// get video on post
|
||||||
|
$video = $post->find('div.post_video_desc', 0);
|
||||||
|
if (is_object($video)) {
|
||||||
|
$video_title = $video->find('div.post_video_title', 0)->plaintext;
|
||||||
|
$video_link = self::URI . ltrim( $video->find('a.lnk', 0)->getAttribute('href'), '/' );
|
||||||
|
$content_suffix .= "<br>Video: <a href='$video_link'>$video_title</a>";
|
||||||
|
$video->outertext = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// get all photos
|
||||||
|
foreach($post->find('div.wall_text > a.page_post_thumb_wrap') as $a) {
|
||||||
|
$result = $this->getPhoto($a);
|
||||||
|
if ($result == null) continue;
|
||||||
|
$a->outertext = '';
|
||||||
|
$content_suffix .= "<br>$result";
|
||||||
|
}
|
||||||
|
|
||||||
|
// get albums
|
||||||
|
foreach($post->find('.page_album_wrap') as $el) {
|
||||||
|
$a = $el->find('.page_album_link', 0);
|
||||||
|
$album_title = $a->find('.page_album_title_text', 0)->getAttribute('title');
|
||||||
|
$album_link = self::URI . ltrim($a->getAttribute('href'), '/');
|
||||||
|
$el->outertext = '';
|
||||||
|
$content_suffix .= "<br>Album: <a href='$album_link'>$album_title</a>";
|
||||||
|
}
|
||||||
|
|
||||||
|
// get photo documents
|
||||||
|
foreach($post->find('a.page_doc_photo_href') as $a) {
|
||||||
|
$doc_link = self::URI . ltrim($a->getAttribute('href'), '/');
|
||||||
|
$doc_gif_label_element = $a->find(".page_gif_label", 0);
|
||||||
|
$doc_title_element = $a->find(".doc_label", 0);
|
||||||
|
|
||||||
|
if (is_object($doc_gif_label_element)) {
|
||||||
|
$gif_preview_img = backgroundToImg($a->find('.page_doc_photo', 0));
|
||||||
|
$content_suffix .= "<br>Gif: <a href='$doc_link'>$gif_preview_img</a>";
|
||||||
|
|
||||||
|
} else if (is_object($doc_title_element)) {
|
||||||
|
$doc_title = $doc_title_element->innertext;
|
||||||
|
$content_suffix .= "<br>Doc: <a href='$doc_link'>$doc_title</a>";
|
||||||
|
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$a->outertext = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// get other documents
|
||||||
|
foreach($post->find('div.page_doc_row') as $div) {
|
||||||
|
$doc_title_element = $div->find("a.page_doc_title", 0);
|
||||||
|
|
||||||
|
if (is_object($doc_title_element)) {
|
||||||
|
$doc_title = $doc_title_element->innertext;
|
||||||
|
$doc_link = self::URI . ltrim($doc_title_element->getAttribute('href'), '/');
|
||||||
|
$content_suffix .= "<br>Doc: <a href='$doc_link'>$doc_title</a>";
|
||||||
|
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$div->outertext = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// get sign
|
||||||
|
$post_author = $pageName;
|
||||||
|
foreach($post->find('a.wall_signed_by') as $a) {
|
||||||
|
$post_author = $a->innertext;
|
||||||
|
$a->outertext = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_object($post->find('div.copy_quote', 0))) {
|
||||||
|
$copy_quote = $post->find('div.copy_quote', 0);
|
||||||
|
if ($copy_post_header = $copy_quote->find('div.copy_post_header', 0)) {
|
||||||
|
$copy_post_header->outertext = '';
|
||||||
|
}
|
||||||
|
$copy_quote_content = $copy_quote->innertext;
|
||||||
|
$copy_quote->outertext = "<br>Reposted: <br>$copy_quote_content";
|
||||||
|
}
|
||||||
|
|
||||||
$item = array();
|
$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), '<br><img>');
|
||||||
|
$item['content'] .= $content_suffix;
|
||||||
if (is_object($post->find('a.page_media_link_title', 0))) {
|
|
||||||
$link = $post->find('a.page_media_link_title', 0)->getAttribute('href');
|
|
||||||
//external link in the post
|
|
||||||
$item['content'] .= "\n\rExternal link: "
|
|
||||||
. str_replace('/away.php?to=', '', urldecode($link));
|
|
||||||
}
|
|
||||||
|
|
||||||
//get video on post
|
|
||||||
if (is_object($post->find('span.post_video_title_content', 0))) {
|
|
||||||
$titleVideo = $post->find('span.post_video_title_content', 0)->plaintext;
|
|
||||||
$linkToVideo = self::URI . $post->find('a.page_post_thumb_video', 0)->getAttribute('href');
|
|
||||||
$item['content'] .= "\n\r {$titleVideo}: {$linkToVideo}";
|
|
||||||
}
|
|
||||||
|
|
||||||
// get post link
|
// get post link
|
||||||
$item['uri'] = self::URI . $post->find('a.post_link', 0)->getAttribute('href');
|
$post_link = $post->find('a.post_link', 0)->getAttribute('href');
|
||||||
|
preg_match("/wall-?\d+_(\d+)/", $post_link, $preg_match_result);
|
||||||
|
$item['post_id'] = intval($preg_match_result[1]);
|
||||||
|
if (substr(self::URI, -1) == '/') {
|
||||||
|
$post_link = self::URI . ltrim($post_link, "/");
|
||||||
|
} else {
|
||||||
|
$post_link = self::URI . $post_link;
|
||||||
|
}
|
||||||
|
$item['uri'] = $post_link;
|
||||||
$item['timestamp'] = $this->getTime($post);
|
$item['timestamp'] = $this->getTime($post);
|
||||||
$item['author'] = $pageName;
|
$item['title'] = $this->getTitle($item['content']);
|
||||||
$this->items[] = $item;
|
$item['author'] = $post_author;
|
||||||
|
if ($is_pinned_post) {
|
||||||
|
// do not append it now
|
||||||
|
$pinned_post_item = $item;
|
||||||
|
} else {
|
||||||
|
$last_post_id = $item['post_id'];
|
||||||
|
$this->items[] = $item;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (is_null($pinned_post_item)) {
|
||||||
|
return;
|
||||||
|
} else if (count($this->items) == 0) {
|
||||||
|
$this->items[] = $pinned_post_item;
|
||||||
|
} else if ($last_post_id < $pinned_post_item['post_id']) {
|
||||||
|
$this->items[] = $pinned_post_item;
|
||||||
|
usort($this->items, function ($item1, $item2) {
|
||||||
|
return $item2['post_id'] - $item1['post_id'];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getPhoto($a) {
|
||||||
|
$onclick = $a->getAttribute('onclick');
|
||||||
|
preg_match('/return showPhoto\(.+?({.*})/', $onclick, $preg_match_result);
|
||||||
|
if (count($preg_match_result) == 0) return;
|
||||||
|
|
||||||
|
$arg = htmlspecialchars_decode( str_replace('queue:1', '"queue":1', $preg_match_result[1]) );
|
||||||
|
$data = json_decode($arg, true);
|
||||||
|
if ($data == null) return;
|
||||||
|
|
||||||
|
$thumb = $data['temp']['base'] . $data['temp']['x_'][0] . ".jpg";
|
||||||
|
$original = '';
|
||||||
|
foreach(array('y_', 'z_', 'w_') as $key) {
|
||||||
|
if (!isset($data['temp'][$key])) continue;
|
||||||
|
$original = $data['temp']['base'] . $data['temp'][$key][0] . ".jpg";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($original) {
|
||||||
|
return "<a href='$original'><img src='$thumb'></a>";
|
||||||
|
} else {
|
||||||
|
return "<img src='$thumb'>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getTitle($content)
|
||||||
|
{
|
||||||
|
preg_match('/^["\w\ \p{Cyrillic}\(\)\?#«»-]+/mu', htmlspecialchars_decode($content), $result);
|
||||||
|
if (count($result) == 0) return "untitled";
|
||||||
|
return $result[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getTime($post)
|
private function getTime($post)
|
||||||
@@ -109,19 +294,9 @@ class VkBridge extends BridgeAbstract
|
|||||||
{
|
{
|
||||||
ini_set('user-agent', 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:53.0) Gecko/20100101 Firefox/53.0');
|
ini_set('user-agent', 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:53.0) Gecko/20100101 Firefox/53.0');
|
||||||
|
|
||||||
$opts = array(
|
$header = array('Accept-language: en', 'Cookie: remixlang=3');
|
||||||
'http' => array(
|
|
||||||
'method' => "GET",
|
|
||||||
'user_agent' => ini_get('user_agent'),
|
|
||||||
'accept_encoding' => 'gzip',
|
|
||||||
'header' => "Accept-language: en\r\n
|
|
||||||
Cookie: remixlang=3\r\n"
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
$context = stream_context_create($opts);
|
return getContents($this->getURI(), $header);
|
||||||
|
|
||||||
return getContents($this->getURI(), false, $context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
138
bridges/YGGTorrentBridge.php
Normal file
138
bridges/YGGTorrentBridge.php
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/* This is a mashup of FlickrExploreBridge by sebsauvage and FlickrTagBridge
|
||||||
|
* by erwang.providing the functionality of both in one.
|
||||||
|
*/
|
||||||
|
class YGGTorrentBridge extends BridgeAbstract {
|
||||||
|
|
||||||
|
const MAINTAINER = 'teromene';
|
||||||
|
const NAME = 'Yggtorrent Bridge';
|
||||||
|
const URI = 'https://yggtorrent.is';
|
||||||
|
const DESCRIPTION = 'Returns torrent search from Yggtorrent';
|
||||||
|
|
||||||
|
const PARAMETERS = array(
|
||||||
|
array(
|
||||||
|
"cat" => array(
|
||||||
|
"name" => "category",
|
||||||
|
"type" => "list",
|
||||||
|
"values" => array(
|
||||||
|
"Toute les catégories" => "all.all",
|
||||||
|
"Film/Vidéo - Toutes les sous-catégories" => "2145.all",
|
||||||
|
"Film/Vidéo - Animation" => "2145.2178",
|
||||||
|
"Film/Vidéo - Animation Série" => "2145.2179",
|
||||||
|
"Film/Vidéo - Concert" => "2145.2180",
|
||||||
|
"Film/Vidéo - Documentaire" => "2145.2181",
|
||||||
|
"Film/Vidéo - Émission TV" => "2145.2182",
|
||||||
|
"Film/Vidéo - Film" => "2145.2183",
|
||||||
|
"Film/Vidéo - Série TV" => "2145.2184",
|
||||||
|
"Film/Vidéo - Spectacle" => "2145.2185",
|
||||||
|
"Film/Vidéo - Sport" => "2145.2186",
|
||||||
|
"Film/Vidéo - Vidéo-clips" => "2145.2186",
|
||||||
|
"Audio - Toutes les sous-catégories" => "2139.all",
|
||||||
|
"Audio - Karaoké" => "2139.2147",
|
||||||
|
"Audio - Musique" => "2139.2148",
|
||||||
|
"Audio - Podcast Radio" => "2139.2150",
|
||||||
|
"Audio - Samples" => "2139.2149",
|
||||||
|
"Jeu vidéo - Toutes les sous-catégories" => "2142.all",
|
||||||
|
"Jeu vidéo - Autre" => "2142.2167",
|
||||||
|
"Jeu vidéo - Linux" => "2142.2159",
|
||||||
|
"Jeu vidéo - MacOS" => "2142.2160",
|
||||||
|
"Jeu vidéo - Microsoft" => "2142.2162",
|
||||||
|
"Jeu vidéo - Nintendo" => "2142.2163",
|
||||||
|
"Jeu vidéo - Smartphone" => "2142.2165",
|
||||||
|
"Jeu vidéo - Sony" => "2142.2164",
|
||||||
|
"Jeu vidéo - Tablette" => "2142.2166",
|
||||||
|
"Jeu vidéo - Windows" => "2142.2161",
|
||||||
|
"eBook - Toutes les sous-catégories" => "2140.all",
|
||||||
|
"eBook - Audio" => "2140.2151",
|
||||||
|
"eBook - Bds" => "2140.2152",
|
||||||
|
"eBook - Comics" => "2140.2153",
|
||||||
|
"eBook - Livres" => "2140.2154",
|
||||||
|
"eBook - Mangas" => "2140.2155",
|
||||||
|
"eBook - Presse" => "2140.2156",
|
||||||
|
"Emulation - Toutes les sous-catégories" => "2141.all",
|
||||||
|
"Emulation - Emulateurs" => "2141.2157",
|
||||||
|
"Emulation - Roms" => "2141.2158",
|
||||||
|
"GPS - Toutes les sous-catégories" => "2141.all",
|
||||||
|
"GPS - Applications" => "2141.2168",
|
||||||
|
"GPS - Cartes" => "2141.2169",
|
||||||
|
"GPS - Divers" => "2141.2170"
|
||||||
|
)
|
||||||
|
),
|
||||||
|
"nom" => array(
|
||||||
|
"name" => "Nom",
|
||||||
|
"description" => "Nom du torrent",
|
||||||
|
"type" => "text"
|
||||||
|
),
|
||||||
|
"description" => array(
|
||||||
|
"name" => "Description",
|
||||||
|
"description" => "Description du torrent",
|
||||||
|
"type" => "text"
|
||||||
|
),
|
||||||
|
"fichier" => array(
|
||||||
|
"name" => "Fichier",
|
||||||
|
"description" => "Fichier du torrent",
|
||||||
|
"type" => "text"
|
||||||
|
),
|
||||||
|
"uploader" => array(
|
||||||
|
"name" => "Uploader",
|
||||||
|
"description" => "Uploader du torrent",
|
||||||
|
"type" => "text"
|
||||||
|
),
|
||||||
|
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
public function collectData() {
|
||||||
|
|
||||||
|
$catInfo = explode(".", $this->getInput("cat"));
|
||||||
|
$category = $catInfo[0];
|
||||||
|
$subcategory = $catInfo[1];
|
||||||
|
|
||||||
|
$html = getSimpleHTMLDOM(self::URI . "/engine/search?name="
|
||||||
|
. $this->getInput("nom")
|
||||||
|
. "&description="
|
||||||
|
. $this->getInput("description")
|
||||||
|
. "&fichier="
|
||||||
|
. $this->getInput("fichier")
|
||||||
|
. "&file="
|
||||||
|
. $this->getInput("uploader")
|
||||||
|
. "&category="
|
||||||
|
. $category
|
||||||
|
. "&sub_category="
|
||||||
|
. $subcategory
|
||||||
|
. "&do=search")
|
||||||
|
or returnServerError("Unable to query Yggtorrent !");
|
||||||
|
|
||||||
|
$count = 0;
|
||||||
|
foreach($html->find(".results", 0)->find("tr") as $row) {
|
||||||
|
$count++;
|
||||||
|
if($count == 1) continue;
|
||||||
|
if($count == 12) break;
|
||||||
|
$item = array();
|
||||||
|
$item["timestamp"] = $row->find(".hidden", 1)->plaintext;
|
||||||
|
$item["title"] = $row->find("a", 1)->plaintext;
|
||||||
|
$torrentData = $this->collectTorrentData($row->find("a", 1)->href);
|
||||||
|
$item["author"] = $torrentData["author"];
|
||||||
|
$item["content"] = $torrentData["content"];
|
||||||
|
$item["seeders"] = $row->find("td", 7)->plaintext;
|
||||||
|
$item["leechers"] = $row->find("td", 8)->plaintext;
|
||||||
|
$item["size"] = $row->find("td", 5)->plaintext;
|
||||||
|
$this->items[] = $item;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function collectTorrentData($url) {
|
||||||
|
|
||||||
|
//For weird reason, the link we get can be invalid, we fix it.
|
||||||
|
$url_full = explode("/", $url);
|
||||||
|
$url_full[6] = urlencode($url_full[6]);
|
||||||
|
$url = implode("/", $url_full);
|
||||||
|
|
||||||
|
$page = getSimpleHTMLDOM($url) or returnServerError("Unable to query Yggtorrent page !");
|
||||||
|
$author = $page->find(".informations", 0)->find("a", 4)->plaintext;
|
||||||
|
$content = $page->find(".default", 1);
|
||||||
|
return array("author" => $author, "content" => $content);
|
||||||
|
}
|
||||||
|
}
|
@@ -110,8 +110,8 @@ class YoutubeBridge extends BridgeAbstract {
|
|||||||
$this->feedName = $this->ytBridgeFixTitle($xml->find('feed > title', 0)->plaintext); // feedName will be used by getName()
|
$this->feedName = $this->ytBridgeFixTitle($xml->find('feed > title', 0)->plaintext); // feedName will be used by getName()
|
||||||
}
|
}
|
||||||
|
|
||||||
private function ytBridgeParseHtmlListing($html, $element_selector, $title_selector){
|
private function ytBridgeParseHtmlListing($html, $element_selector, $title_selector, $add_parsed_items = true) {
|
||||||
$limit = 10;
|
$limit = $add_parsed_items ? 10 : INF;
|
||||||
$count = 0;
|
$count = 0;
|
||||||
foreach($html->find($element_selector) as $element) {
|
foreach($html->find($element_selector) as $element) {
|
||||||
if($count < $limit) {
|
if($count < $limit) {
|
||||||
@@ -122,12 +122,15 @@ class YoutubeBridge extends BridgeAbstract {
|
|||||||
$vid = substr($vid, 0, strpos($vid, '&') ?: strlen($vid));
|
$vid = substr($vid, 0, strpos($vid, '&') ?: strlen($vid));
|
||||||
$title = $this->ytBridgeFixTitle($element->find($title_selector, 0)->plaintext);
|
$title = $this->ytBridgeFixTitle($element->find($title_selector, 0)->plaintext);
|
||||||
if($title != '[Private Video]' && strpos($vid, 'googleads') === false) {
|
if($title != '[Private Video]' && strpos($vid, 'googleads') === false) {
|
||||||
$this->ytBridgeQueryVideoInfo($vid, $author, $desc, $time);
|
if ($add_parsed_items) {
|
||||||
$this->ytBridgeAddItem($vid, $title, $author, $desc, $time);
|
$this->ytBridgeQueryVideoInfo($vid, $author, $desc, $time);
|
||||||
|
$this->ytBridgeAddItem($vid, $title, $author, $desc, $time);
|
||||||
|
}
|
||||||
$count++;
|
$count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return $count;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function ytBridgeFixTitle($title) {
|
private function ytBridgeFixTitle($title) {
|
||||||
@@ -137,10 +140,8 @@ class YoutubeBridge extends BridgeAbstract {
|
|||||||
|
|
||||||
private function ytGetSimpleHTMLDOM($url){
|
private function ytGetSimpleHTMLDOM($url){
|
||||||
return getSimpleHTMLDOM($url,
|
return getSimpleHTMLDOM($url,
|
||||||
$use_include_path = false,
|
$header = array(),
|
||||||
$context = null,
|
$opts = array(),
|
||||||
$offset = 0,
|
|
||||||
$maxLen = null,
|
|
||||||
$lowercase = true,
|
$lowercase = true,
|
||||||
$forceTagsClosed = true,
|
$forceTagsClosed = true,
|
||||||
$target_charset = DEFAULT_TARGET_CHARSET,
|
$target_charset = DEFAULT_TARGET_CHARSET,
|
||||||
@@ -176,11 +177,20 @@ class YoutubeBridge extends BridgeAbstract {
|
|||||||
}
|
}
|
||||||
} elseif($this->getInput('p')) { /* playlist mode */
|
} elseif($this->getInput('p')) { /* playlist mode */
|
||||||
$this->request = $this->getInput('p');
|
$this->request = $this->getInput('p');
|
||||||
|
$url_feed = self::URI . 'feeds/videos.xml?playlist_id=' . urlencode($this->request);
|
||||||
$url_listing = self::URI . 'playlist?list=' . urlencode($this->request);
|
$url_listing = self::URI . 'playlist?list=' . urlencode($this->request);
|
||||||
$html = $this->ytGetSimpleHTMLDOM($url_listing)
|
$html = $this->ytGetSimpleHTMLDOM($url_listing)
|
||||||
or returnServerError("Could not request YouTube. Tried:\n - $url_listing");
|
or returnServerError("Could not request YouTube. Tried:\n - $url_listing");
|
||||||
$this->ytBridgeParseHtmlListing($html, 'tr.pl-video', '.pl-video-title a');
|
$item_count = $this->ytBridgeParseHtmlListing($html, 'tr.pl-video', '.pl-video-title a', false);
|
||||||
|
if ($item_count <= 15 && ($xml = $this->ytGetSimpleHTMLDOM($url_feed))) {
|
||||||
|
$this->ytBridgeParseXmlFeed($xml);
|
||||||
|
} else {
|
||||||
|
$this->ytBridgeParseHtmlListing($html, 'tr.pl-video', '.pl-video-title a');
|
||||||
|
}
|
||||||
$this->feedName = 'Playlist: ' . str_replace(' - YouTube', '', $html->find('title', 0)->plaintext); // feedName will be used by getName()
|
$this->feedName = 'Playlist: ' . str_replace(' - YouTube', '', $html->find('title', 0)->plaintext); // feedName will be used by getName()
|
||||||
|
usort($this->items, function ($item1, $item2) {
|
||||||
|
return $item2['timestamp'] - $item1['timestamp'];
|
||||||
|
});
|
||||||
} elseif($this->getInput('s')) { /* search mode */
|
} elseif($this->getInput('s')) { /* search mode */
|
||||||
$this->request = $this->getInput('s');
|
$this->request = $this->getInput('s');
|
||||||
$page = 1;
|
$page = 1;
|
||||||
@@ -197,7 +207,7 @@ class YoutubeBridge extends BridgeAbstract {
|
|||||||
$html = $this->ytGetSimpleHTMLDOM($url_listing)
|
$html = $this->ytGetSimpleHTMLDOM($url_listing)
|
||||||
or returnServerError("Could not request YouTube. Tried:\n - $url_listing");
|
or returnServerError("Could not request YouTube. Tried:\n - $url_listing");
|
||||||
|
|
||||||
$this->ytBridgeParseHtmlListing($html, 'div.yt-lockup', 'h3');
|
$this->ytBridgeParseHtmlListing($html, 'div.yt-lockup', 'h3 > a');
|
||||||
$this->feedName = 'Search: ' . str_replace(' - YouTube', '', $html->find('title', 0)->plaintext); // feedName will be used by getName()
|
$this->feedName = 'Search: ' . str_replace(' - YouTube', '', $html->find('title', 0)->plaintext); // feedName will be used by getName()
|
||||||
} else { /* no valid mode */
|
} else { /* no valid mode */
|
||||||
returnClientError("You must either specify either:\n - YouTube
|
returnClientError("You must either specify either:\n - YouTube
|
||||||
|
34
index.php
34
index.php
@@ -19,6 +19,10 @@ define('PROXY_BYBRIDGE', false);
|
|||||||
// Comment this line or keep PROXY_NAME empty to display PROXY_URL instead
|
// Comment this line or keep PROXY_NAME empty to display PROXY_URL instead
|
||||||
define('PROXY_NAME', 'Hidden Proxy Name');
|
define('PROXY_NAME', 'Hidden Proxy Name');
|
||||||
|
|
||||||
|
// Allows the operator to specify custom cache timeouts via '&_cache_timeout=3600'
|
||||||
|
// true: enabled, false: disabled (default)
|
||||||
|
define('CUSTOM_CACHE_TIMEOUT', false);
|
||||||
|
|
||||||
date_default_timezone_set('UTC');
|
date_default_timezone_set('UTC');
|
||||||
error_reporting(0);
|
error_reporting(0);
|
||||||
|
|
||||||
@@ -73,6 +77,12 @@ if(!extension_loaded('libxml'))
|
|||||||
if(!extension_loaded('mbstring'))
|
if(!extension_loaded('mbstring'))
|
||||||
die('"mbstring" extension not loaded. Please check "php.ini"');
|
die('"mbstring" extension not loaded. Please check "php.ini"');
|
||||||
|
|
||||||
|
if(!extension_loaded('simplexml'))
|
||||||
|
die('"simplexml" extension not loaded. Please check "php.ini"');
|
||||||
|
|
||||||
|
if(!extension_loaded('curl'))
|
||||||
|
die('"curl" extension not loaded. Please check "php.ini"');
|
||||||
|
|
||||||
// configuration checks
|
// configuration checks
|
||||||
if(ini_get('allow_url_fopen') !== "1")
|
if(ini_get('allow_url_fopen') !== "1")
|
||||||
die('"allow_url_fopen" is not set to "1". Please check "php.ini');
|
die('"allow_url_fopen" is not set to "1". Please check "php.ini');
|
||||||
@@ -168,6 +178,16 @@ try {
|
|||||||
define('NOPROXY', true);
|
define('NOPROXY', true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Custom cache timeout
|
||||||
|
$cache_timeout = -1;
|
||||||
|
if(array_key_exists('_cache_timeout', $params)) {
|
||||||
|
if(!CUSTOM_CACHE_TIMEOUT) {
|
||||||
|
throw new \HttpException('This server doesn\'t support "_cache_timeout"!');
|
||||||
|
}
|
||||||
|
|
||||||
|
$cache_timeout = filter_var($params['_cache_timeout'], FILTER_VALIDATE_INT);
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize cache
|
// Initialize cache
|
||||||
$cache = Cache::create('FileCache');
|
$cache = Cache::create('FileCache');
|
||||||
$cache->setPath(CACHE_DIR);
|
$cache->setPath(CACHE_DIR);
|
||||||
@@ -178,11 +198,17 @@ try {
|
|||||||
unset($params['bridge']);
|
unset($params['bridge']);
|
||||||
unset($params['format']);
|
unset($params['format']);
|
||||||
unset($params['_noproxy']);
|
unset($params['_noproxy']);
|
||||||
|
unset($params['_cache_timeout']);
|
||||||
|
|
||||||
// Load cache & data
|
// Load cache & data
|
||||||
try {
|
try {
|
||||||
$bridge->setCache($cache);
|
$bridge->setCache($cache);
|
||||||
|
$bridge->setCacheTimeout($cache_timeout);
|
||||||
$bridge->setDatas($params);
|
$bridge->setDatas($params);
|
||||||
|
} catch(Error $e) {
|
||||||
|
http_response_code($e->getCode());
|
||||||
|
header('Content-Type: text/html');
|
||||||
|
die(buildBridgeException($e, $bridge));
|
||||||
} catch(Exception $e) {
|
} catch(Exception $e) {
|
||||||
http_response_code($e->getCode());
|
http_response_code($e->getCode());
|
||||||
header('Content-Type: text/html');
|
header('Content-Type: text/html');
|
||||||
@@ -195,10 +221,14 @@ try {
|
|||||||
$format->setItems($bridge->getItems());
|
$format->setItems($bridge->getItems());
|
||||||
$format->setExtraInfos($bridge->getExtraInfos());
|
$format->setExtraInfos($bridge->getExtraInfos());
|
||||||
$format->display();
|
$format->display();
|
||||||
} catch(Exception $e) {
|
} catch(Error $e) {
|
||||||
http_response_code($e->getCode());
|
http_response_code($e->getCode());
|
||||||
header('Content-Type: text/html');
|
header('Content-Type: text/html');
|
||||||
die(buildTransformException($e, $bridge));
|
die(buildTransformException($e, $bridge));
|
||||||
|
} catch(Exception $e) {
|
||||||
|
http_response_code($e->getCode());
|
||||||
|
header('Content-Type: text/html');
|
||||||
|
die(buildBridgeException($e, $bridge));
|
||||||
}
|
}
|
||||||
|
|
||||||
die;
|
die;
|
||||||
@@ -273,7 +303,7 @@ EOD;
|
|||||||
echo $inactiveBridges;
|
echo $inactiveBridges;
|
||||||
?>
|
?>
|
||||||
<section class="footer">
|
<section class="footer">
|
||||||
<a href="https://github.com/RSS-Bridge/rss-bridge">RSS-Bridge 2017-08-19 ~ Public Domain</a><br />
|
<a href="https://github.com/RSS-Bridge/rss-bridge">RSS-Bridge 2018-04-20 ~ Public Domain</a><br />
|
||||||
<?= $activeFoundBridgeCount; ?>/<?= count($bridgeList) ?> active bridges. <br />
|
<?= $activeFoundBridgeCount; ?>/<?= count($bridgeList) ?> active bridges. <br />
|
||||||
<?php
|
<?php
|
||||||
if($activeFoundBridgeCount !== count($bridgeList)) {
|
if($activeFoundBridgeCount !== count($bridgeList)) {
|
||||||
|
@@ -14,6 +14,7 @@ abstract class BridgeAbstract implements BridgeInterface {
|
|||||||
protected $items = array();
|
protected $items = array();
|
||||||
protected $inputs = array();
|
protected $inputs = array();
|
||||||
protected $queriedContext = '';
|
protected $queriedContext = '';
|
||||||
|
protected $cacheTimeout;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return cachable datas (extrainfos and items) stored in the bridge
|
* Return cachable datas (extrainfos and items) stored in the bridge
|
||||||
@@ -171,7 +172,7 @@ abstract class BridgeAbstract implements BridgeInterface {
|
|||||||
if(!is_null($this->cache)) {
|
if(!is_null($this->cache)) {
|
||||||
$time = $this->cache->getTime();
|
$time = $this->cache->getTime();
|
||||||
if($time !== false
|
if($time !== false
|
||||||
&& (time() - static::CACHE_TIMEOUT < $time)
|
&& (time() - $this->getCacheTimeout() < $time)
|
||||||
&& (!defined('DEBUG') || DEBUG !== true)) {
|
&& (!defined('DEBUG') || DEBUG !== true)) {
|
||||||
$cached = $this->cache->loadData();
|
$cached = $this->cache->loadData();
|
||||||
if(isset($cached['items']) && isset($cached['extraInfos'])) {
|
if(isset($cached['items']) && isset($cached['extraInfos'])) {
|
||||||
@@ -268,4 +269,17 @@ abstract class BridgeAbstract implements BridgeInterface {
|
|||||||
public function setCache(\CacheInterface $cache){
|
public function setCache(\CacheInterface $cache){
|
||||||
$this->cache = $cache;
|
$this->cache = $cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setCacheTimeout($timeout){
|
||||||
|
if(is_numeric($timeout) && ($timeout < 1 || $timeout > 86400)) {
|
||||||
|
$this->cacheTimeout = static::CACHE_TIMEOUT;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->cacheTimeout = $timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCacheTimeout(){
|
||||||
|
return isset($this->cacheTimeout) ? $this->cacheTimeout : static::CACHE_TIMEOUT;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -68,4 +68,20 @@ interface BridgeInterface {
|
|||||||
* @param object CacheInterface The cache instance
|
* @param object CacheInterface The cache instance
|
||||||
*/
|
*/
|
||||||
public function setCache(\CacheInterface $cache);
|
public function setCache(\CacheInterface $cache);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the timeout for clearing the cache files. The timeout must be
|
||||||
|
* specified between 1..86400 seconds (max. 24 hours). The default timeout
|
||||||
|
* (specified by the bridge maintainer) applies for invalid values.
|
||||||
|
*
|
||||||
|
* @param int $timeout The cache timeout in seconds
|
||||||
|
*/
|
||||||
|
public function setCacheTimeout($timeout);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the cache timeout
|
||||||
|
*
|
||||||
|
* @return int Cache timeout
|
||||||
|
*/
|
||||||
|
public function getCacheTimeout();
|
||||||
}
|
}
|
||||||
|
@@ -54,7 +54,7 @@ function buildGitHubIssueQuery($title, $body, $labels = null, $maintainer = null
|
|||||||
* provided parameter are invalid
|
* provided parameter are invalid
|
||||||
*/
|
*/
|
||||||
function buildBridgeException($e, $bridge){
|
function buildBridgeException($e, $bridge){
|
||||||
if(!($e instanceof \Exception) || !($bridge instanceof \BridgeInterface)) {
|
if(( !($e instanceof \Exception) && !($e instanceof \Error)) || !($bridge instanceof \BridgeInterface)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,7 +85,7 @@ unable to receive or process the remote website's content!";
|
|||||||
* provided parameter are invalid
|
* provided parameter are invalid
|
||||||
*/
|
*/
|
||||||
function buildTransformException($e, $bridge){
|
function buildTransformException($e, $bridge){
|
||||||
if(!($e instanceof \Exception) || !($bridge instanceof \BridgeInterface)) {
|
if(( !($e instanceof \Exception) && !($e instanceof \Error)) || !($bridge instanceof \BridgeInterface)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,77 +1,45 @@
|
|||||||
<?php
|
<?php
|
||||||
function getContents($url,
|
function getContents($url, $header = array(), $opts = array()){
|
||||||
$use_include_path = false,
|
$ch = curl_init($url);
|
||||||
$context = null,
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
$offset = 0,
|
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
|
||||||
$maxlen = null){
|
|
||||||
$contextOptions = array(
|
|
||||||
'http' => array(
|
|
||||||
'user_agent' => ini_get('user_agent'),
|
|
||||||
'accept_encoding' => 'gzip'
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
if(defined('PROXY_URL') && !defined('NOPROXY')) {
|
if(is_array($header) && count($header) !== 0)
|
||||||
$contextOptions['http']['proxy'] = PROXY_URL;
|
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
|
||||||
$contextOptions['http']['request_fulluri'] = true;
|
|
||||||
|
|
||||||
if(is_null($context)) {
|
curl_setopt($ch, CURLOPT_USERAGENT, ini_get('user_agent'));
|
||||||
$context = stream_context_create($contextOptions);
|
curl_setopt($ch, CURLOPT_ENCODING, '');
|
||||||
} else {
|
curl_setopt($ch, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);
|
||||||
$prevContext = $context;
|
|
||||||
if(!stream_context_set_option($context, $contextOptions)) {
|
if(is_array($opts)) {
|
||||||
$context = $prevContext;
|
foreach($opts as $key => $value) {
|
||||||
}
|
curl_setopt($ch, $key, $value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(is_null($maxlen)) {
|
if(defined('PROXY_URL') && !defined('NOPROXY')) {
|
||||||
$content = file_get_contents($url, $use_include_path, $context, $offset);
|
curl_setopt($ch, CURLOPT_PROXY, PROXY_URL);
|
||||||
} else {
|
|
||||||
$content = file_get_contents($url, $use_include_path, $context, $offset, $maxlen);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$content = curl_exec($ch);
|
||||||
|
curl_close($ch);
|
||||||
|
|
||||||
if($content === false)
|
if($content === false)
|
||||||
debugMessage('Cant\'t download ' . $url);
|
debugMessage('Cant\'t download ' . $url);
|
||||||
|
|
||||||
// handle compressed data
|
|
||||||
foreach($http_response_header as $header) {
|
|
||||||
if(stristr($header, 'content-encoding')) {
|
|
||||||
switch(true) {
|
|
||||||
case stristr($header, 'gzip'):
|
|
||||||
$content = gzinflate(substr($content, 10, -8));
|
|
||||||
break;
|
|
||||||
case stristr($header, 'compress'):
|
|
||||||
//TODO
|
|
||||||
case stristr($header, 'deflate'):
|
|
||||||
//TODO
|
|
||||||
case stristr($header, 'brotli'):
|
|
||||||
//TODO
|
|
||||||
returnServerError($header . '=> Not implemented yet');
|
|
||||||
break;
|
|
||||||
case stristr($header, 'identity'):
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
returnServerError($header . '=> Unknown compression');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $content;
|
return $content;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getSimpleHTMLDOM($url,
|
function getSimpleHTMLDOM($url,
|
||||||
$use_include_path = false,
|
$header = array(),
|
||||||
$context = null,
|
$opts = array(),
|
||||||
$offset = 0,
|
|
||||||
$maxLen = null,
|
|
||||||
$lowercase = true,
|
$lowercase = true,
|
||||||
$forceTagsClosed = true,
|
$forceTagsClosed = true,
|
||||||
$target_charset = DEFAULT_TARGET_CHARSET,
|
$target_charset = DEFAULT_TARGET_CHARSET,
|
||||||
$stripRN = true,
|
$stripRN = true,
|
||||||
$defaultBRText = DEFAULT_BR_TEXT,
|
$defaultBRText = DEFAULT_BR_TEXT,
|
||||||
$defaultSpanText = DEFAULT_SPAN_TEXT){
|
$defaultSpanText = DEFAULT_SPAN_TEXT){
|
||||||
$content = getContents($url, $use_include_path, $context, $offset, $maxLen);
|
$content = getContents($url, $header, $opts);
|
||||||
return str_get_html($content,
|
return str_get_html($content,
|
||||||
$lowercase,
|
$lowercase,
|
||||||
$forceTagsClosed,
|
$forceTagsClosed,
|
||||||
@@ -89,10 +57,8 @@ $defaultSpanText = DEFAULT_SPAN_TEXT){
|
|||||||
*/
|
*/
|
||||||
function getSimpleHTMLDOMCached($url,
|
function getSimpleHTMLDOMCached($url,
|
||||||
$duration = 86400,
|
$duration = 86400,
|
||||||
$use_include_path = false,
|
$header = array(),
|
||||||
$context = null,
|
$opts = array(),
|
||||||
$offset = 0,
|
|
||||||
$maxLen = null,
|
|
||||||
$lowercase = true,
|
$lowercase = true,
|
||||||
$forceTagsClosed = true,
|
$forceTagsClosed = true,
|
||||||
$target_charset = DEFAULT_TARGET_CHARSET,
|
$target_charset = DEFAULT_TARGET_CHARSET,
|
||||||
@@ -116,7 +82,7 @@ $defaultSpanText = DEFAULT_SPAN_TEXT){
|
|||||||
&& (!defined('DEBUG') || DEBUG !== true)) { // Contents within duration
|
&& (!defined('DEBUG') || DEBUG !== true)) { // Contents within duration
|
||||||
$content = $cache->loadData();
|
$content = $cache->loadData();
|
||||||
} else { // Content not within duration
|
} else { // Content not within duration
|
||||||
$content = getContents($url, $use_include_path, $context, $offset, $maxLen);
|
$content = getContents($url, $header, $opts);
|
||||||
if($content !== false) {
|
if($content !== false) {
|
||||||
$cache->saveData($content);
|
$cache->saveData($content);
|
||||||
}
|
}
|
||||||
|
35
lib/html.php
35
lib/html.php
@@ -75,8 +75,24 @@ CARD;
|
|||||||
. ((defined('PROXY_NAME') && PROXY_NAME) ? PROXY_NAME : PROXY_URL)
|
. ((defined('PROXY_NAME') && PROXY_NAME) ? PROXY_NAME : PROXY_URL)
|
||||||
. ')</label><br />'
|
. ')</label><br />'
|
||||||
. PHP_EOL;
|
. PHP_EOL;
|
||||||
}
|
} if(CUSTOM_CACHE_TIMEOUT) {
|
||||||
|
$idArg = 'arg-'
|
||||||
|
. urlencode($bridgeName)
|
||||||
|
. '-'
|
||||||
|
. urlencode('_cache_timeout');
|
||||||
|
|
||||||
|
$card .= '<label for="'
|
||||||
|
. $idArg
|
||||||
|
. '">Cache timeout in seconds : </label>'
|
||||||
|
. PHP_EOL;
|
||||||
|
|
||||||
|
$card .= '<input id="'
|
||||||
|
. $idArg
|
||||||
|
. '" type="number" value="'
|
||||||
|
. $bridge->getCacheTimeout()
|
||||||
|
. '" name="_cache_timeout" /><br />'
|
||||||
|
. PHP_EOL;
|
||||||
|
}
|
||||||
$card .= $getHelperButtonsFormat($formats);
|
$card .= $getHelperButtonsFormat($formats);
|
||||||
} else {
|
} else {
|
||||||
$card .= '<span style="font-weight: bold;">Inactive</span>';
|
$card .= '<span style="font-weight: bold;">Inactive</span>';
|
||||||
@@ -251,6 +267,23 @@ CARD;
|
|||||||
. ((defined('PROXY_NAME') && PROXY_NAME) ? PROXY_NAME : PROXY_URL)
|
. ((defined('PROXY_NAME') && PROXY_NAME) ? PROXY_NAME : PROXY_URL)
|
||||||
. ')</label><br />'
|
. ')</label><br />'
|
||||||
. PHP_EOL;
|
. PHP_EOL;
|
||||||
|
} if(CUSTOM_CACHE_TIMEOUT) {
|
||||||
|
$idArg = 'arg-'
|
||||||
|
. urlencode($bridgeName)
|
||||||
|
. '-'
|
||||||
|
. urlencode('_cache_timeout');
|
||||||
|
|
||||||
|
$card .= '<label for="'
|
||||||
|
. $idArg
|
||||||
|
. '">Cache timeout in seconds : </label>'
|
||||||
|
. PHP_EOL;
|
||||||
|
|
||||||
|
$card .= '<input id="'
|
||||||
|
. $idArg
|
||||||
|
. '" type="number" value="'
|
||||||
|
. $bridge->getCacheTimeout()
|
||||||
|
. '" name="_cache_timeout" /><br />'
|
||||||
|
. PHP_EOL;
|
||||||
}
|
}
|
||||||
$card .= $getHelperButtonsFormat($formats);
|
$card .= $getHelperButtonsFormat($formats);
|
||||||
} else {
|
} else {
|
||||||
|
@@ -5,7 +5,6 @@ html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockq
|
|||||||
border: 0;
|
border: 0;
|
||||||
outline: 0;
|
outline: 0;
|
||||||
font-size: 100%;
|
font-size: 100%;
|
||||||
font: inherit;
|
|
||||||
vertical-align: baseline;
|
vertical-align: baseline;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -111,3 +110,8 @@ button.backbutton, button.rss-feed {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
|
||||||
|
max-width: 100%;
|
||||||
|
|
||||||
|
}
|
Reference in New Issue
Block a user