1
0
mirror of https://github.com/RSS-Bridge/rss-bridge.git synced 2025-08-25 17:31:25 +02:00

Compare commits

...

18 Commits

Author SHA1 Message Date
logmanoriginal
4c5013bc82 [index] Bump release version to 2018-06-10 2018-06-10 22:14:58 +02:00
Eugene Molotov
7dc09db9ca [VkBridge] More beatifications and fixes (#712)
* Add one more selector for article_author_selector
* Extend video parsing
* Add poll parsing
2018-06-10 22:09:50 +02:00
hunhejj
d92da8f0f7 Add cUrl error message and code to the debugMessage (#711) 2018-06-10 22:08:45 +02:00
logmanoriginal
064ba456e8 [InstagramBridge] Fix broken compatibility for media_type parameter
The media_type parameter was recently replaced by media_type_u (for
user mode) and media_type_h (for hashtag mode). This was necessary
in order to add the media type 'story' only for the user mode.

"The reason for that is that RSS-Bridge supports multiple parameters
with the same name if and only if they contain the exact same value.
Here, hashtags don't have stories, so it would not be possible to
pass "story" as a parameter. This is a design mistake that I made
when I added support for hashtags."

-- 8770c87389 (r28871502)

However as pointed out this change breaks existing feeds as the
parameter name is no longer compatible to previous implementations.

This commit changes the implementation to provide the old media_type
parameter globally and check for invalid options on each request. If
a user uses the 'story' option in history mode the bridge returns a
client error.

references 8770c87
references #694
fixes #696
fixes #699
fixes #701
2018-05-29 12:52:31 +02:00
LogMANOriginal
8ac8e08abf Add user config (#653)
Uses the parse_ini_file function to load default settings from the default configuration file 'config.default.ini.php'. Optionally loads custom settings from 'config.ini.php' to replace the default
values.
2018-05-29 11:52:17 +02:00
rogerdc
c4f32c31a8 Add ChristianDailyReporterBridge (#697) 2018-05-29 11:28:22 +02:00
Eugene Molotov
4369e077c2 [VkBridge] Fixed image src link generating for photo (#700) 2018-05-29 11:01:54 +02:00
sysadminstory
1045850043 [DealabsBridge] Follow site changes, fix unhandled case (#703)
* [DealabsBridge] Follow site changes, fix unhandled case

- Fixed the case where no discount was shown
- Changed some CSS class to follow the website changes
2018-05-29 10:52:13 +02:00
teromene
2d8f4dc3c5 Fix space in URL resulting in API errors. 2018-05-05 18:10:19 +01:00
teromene
779b638fb4 Added ElloBridge. Closes #683 2018-05-05 18:06:27 +01:00
teromene
3ca59392c2 Fix for crashes when accessing FileCache in case it has been purged/not created yet. 2018-05-05 18:05:48 +01:00
teromene
9b34b68180 Do not use an external service in order to fetch the favicon. 2018-05-05 13:55:38 +01:00
teromene
79ebdc4b39 Warn the user when trying to fetch a non-public facebook page. 2018-05-05 13:49:49 +01:00
teromene
8770c87389 Added support for stories in InstagramBridge. Closes #665
Renamed parameters as stories are only available in user mode.
Use a regex instead of HTML parsing to extract the JSON, as it is way faster.
2018-05-05 13:00:59 +01:00
Eugene Molotov
c1e3352218 [VkBridge] Extended article link parsing (#685)
* [VkBridge] Extended article link parsing
2018-05-05 12:03:54 +02:00
Grégory T
00570ce1b4 [ETTVBridge] New bridge, first push (#680)
* [ETTVBridge] New bridge
2018-04-30 23:18:39 +02:00
teromene
df33dcff4e [YGGTorrentBridge] URL encode the first parts of the requests. 2018-04-26 22:57:18 +01:00
Nicolas Delsaux
e60b5ab193 Mise à jour du bridge pour WorldOfTanks (#527)
* Mise à jour de l'un de mes bridges fétiches
2018-04-22 12:58:07 +02:00
16 changed files with 550 additions and 114 deletions

1
.gitignore vendored
View File

@@ -227,6 +227,7 @@ pip-log.txt
/cache
/whitelist.txt
DEBUG
config.ini.php
######################
## VisualStudioCode ##

View File

@@ -0,0 +1,25 @@
<?php
class ChristianDailyReporterBridge extends BridgeAbstract {
const MAINTAINER = 'rogerdc';
const NAME = 'Christian Daily Reporter Unofficial RSS';
const URI = 'https://www.christiandailyreporter.com/';
const DESCRIPTION = 'The Unofficial Christian Daily Reporter RSS';
// const CACHE_TIMEOUT = 86400; // 1 day
public function collectData() {
$uri = 'https://www.christiandailyreporter.com/';
$html = getSimpleHTMLDOM($uri)
or returnServerError('Could not request Christian Daily Reporter.');
foreach($html->find('div.top p a,div.column p a') as $element) {
$item = array();
// Title
$item['title'] = $element->innertext;
// URL
$item['uri'] = $element->href;
$this->items[] = $item;
}
}
}

View File

@@ -148,7 +148,6 @@ class DealabsBridge extends BridgeAbstract {
'cept-thread-image-link',
'imgFrame',
'imgFrame--noBorder',
'box--all-i',
'thread-listImgCell',
)
);
@@ -179,6 +178,7 @@ class DealabsBridge extends BridgeAbstract {
' ', /* Notice this is a space! */
array(
'cept-description-container',
'userHtml',
'overflow--wrap-break',
'size--all-s',
'size--fromW3-m',
@@ -302,12 +302,18 @@ class DealabsBridge extends BridgeAbstract {
private function getReduction($deal)
{
if($deal->find('span[class*=mute--text text--lineThrough]', 0) != null) {
$discountHtml = $deal->find('span[class=space--ml-1 size--all-l size--fromW3-xl]', 0);
if($discountHtml != null) {
$discount = $discountHtml->plaintext;
} else {
$discount = '';
}
return '<div>Réduction : <span style="text-decoration: line-through;">'
. $deal->find(
'span[class*=mute--text text--lineThrough]', 0
)->plaintext
. '</span>&nbsp;'
. $deal->find('span[class=space--ml-1 size--all-l size--fromW3-xl]', 0)->plaintext
. $discount
. '</div>';
} else {
return '';
@@ -412,6 +418,7 @@ class DealabsBridge extends BridgeAbstract {
'November',
'December'
);
$string = str_replace('Actualisé ', '', $string);
$date_str = trim(str_replace($month_fr, $month_en, $string));
if(!preg_match('/[0-9]{4}/', $string)) {

142
bridges/ETTVBridge.php Normal file
View File

@@ -0,0 +1,142 @@
<?php
class ETTVBridge extends BridgeAbstract {
const MAINTAINER = "GregThib";
const NAME = 'ETTV';
const URI = 'https://www.ettv.tv/';
const DESCRIPTION = 'Returns list of 20 latest torrents for a specific search.';
const CACHE_TIMEOUT = 14400; // 4 hours
const PARAMETERS = array( array(
'query' => array(
'name' => 'Keywords',
'required' => true
),
'cat' => array(
'type' => 'list',
'name' => 'Category',
'values' => array(
'(ALL TYPES)' => '0',
'Anime: Movies' => '73',
'Anime: Dubbed/Subbed' => '74',
'Anime: Others' => '75',
'Books: Ebooks' => '53',
'Books: Magazines' => '54',
'Books: Comics' => '55',
'Books: Audio' => '56',
'Books: Others' => '68',
'Games: Windows' => '57',
'Games: Android' => '58',
'Games: Others' => '71',
'Movies: HD 1080p' => '1',
'Movies: HD 720p' => '2',
'Movies: UltraHD/4K' => '3',
'Movies: XviD' => '42',
'Movies: X264/H264' => '47',
'Movies: 3D' => '49',
'Movies: Dubs/Dual Audio' => '51',
'Movies: CAM/TS' => '65',
'Movies: BluRay Disc/Remux' => '66',
'Movies: DVDR' => '67',
'Movies: HEVC/x265' => '76',
'Music: MP3' => '59',
'Music: FLAC' => '60',
'Music: Music Videos' => '61',
'Music: Others' => '69',
'Software: Windows' => '62',
'Software: Android' => '63',
'Software: Mac' => '64',
'Software: Others' => '70',
'TV: HD/X264/H264' => '41',
'TV: SD/X264/H264' => '5',
'TV: TV Packs' => '7',
'TV: SD/XVID' => '50',
'TV: Sport' => '72',
'TV: HEVC/x265' => '77',
'Unsorted: Unsorted' => '78'
),
'defaultValue' => '(ALL TYPES)'
),
'status' => array(
'type' => 'list',
'name' => 'Status',
'values' => array(
'Active Transfers' => '0',
'Included Dead' => '1',
'Only Dead' => '2'
),
'defaultValue' => 'Included Dead'
),
'lang' => array(
'type' => 'list',
'name' => 'Lang',
'values' => array(
'(ALL)' => '0',
'Arabic' => '17',
'Chinese ' => '10',
'Danish' => '13',
'Dutch' => '11',
'English' => '1',
'Finnish' => '18',
'French' => '2',
'German' => '3',
'Greek' => '15',
'Hindi' => '8',
'Italian' => '4',
'Japanese' => '5',
'Korean' => '9',
'Polish' => '14',
'Russian' => '7',
'Spanish' => '6',
'Turkish' => '16'
),
'defaultValue' => '(ALL)'
)
));
public function collectData(){
// No control on inputs, because all have defaultValue set
$query_str = 'torrents-search.php';
$query_str .= '?search=' . urlencode('+'.str_replace(' ', ' +', $this->getInput('query')));
$query_str .= '&cat=' . $this->getInput('cat');
$query_str .= 'incldead&=' . $this->getInput('status');
$query_str .= '&lang=' . $this->getInput('lang');
$query_str .= '&sort=id&order=desc';
// Get results page
$html = getSimpleHTMLDOM(self::URI . $query_str)
or returnServerError('Could not request ' . $this->getName());
// Loop on each entry
foreach($html->find('table.table tr') as $element) {
if($element->parent->tag == 'thead') continue;
$entry = $element->find('td', 1)->find('a', 0);
// retrieve result page to get more details
$link = rtrim(self::URI, "/") . $entry->href;
$page = getSimpleHTMLDOM($link)
or returnServerError('Could not request page ' . $link);
// get details & download links
$details = $page->find('fieldset.download table', 0); // WHAT?? It should be the second one…
$dllinks = $page->find('div#downloadbox table', 0);
// fill item
$item = array();
$item['author'] = $details->children(6)->children(1)->plaintext;
$item['title'] = $entry->title;
$item['uri'] = $dllinks->children(0)->children(0)->children(0)->href;
$item['timestamp'] = strtotime($details->children(7)->children(1)->plaintext);
$item['content'] = '';
$item['content'] .= '<br/><b>Name: </b>' . $details->children(0)->children(1)->innertext;
$item['content'] .= '<br/><b>Lang: </b>' . $details->children(3)->children(1)->innertext;
$item['content'] .= '<br/><b>Size: </b>' . $details->children(4)->children(1)->innertext;
$item['content'] .= '<br/><b>Hash: </b>' . $details->children(5)->children(1)->innertext;
foreach($dllinks->children(0)->children(1)->find('a') as $dl) {
$item['content'] .= '<br/>' . $dl->outertext;
}
$item['content'] .= '<br/><br/>' . $details->children(1)->children(0)->innertext;
$this->items[] = $item;
}
}
}

146
bridges/ElloBridge.php Normal file
View File

@@ -0,0 +1,146 @@
<?php
class ElloBridge extends BridgeAbstract {
const MAINTAINER = 'teromene';
const NAME = 'Ello Bridge';
const URI = 'https://ello.co/';
const CACHE_TIMEOUT = 4800; //2hours
const DESCRIPTION = 'Returns the newest posts for Ello';
const PARAMETERS = array(
'By User' => array(
'u' => array(
'name' => 'Username',
'required' => true,
'title' => 'Username'
)
),
'Search' => array(
's' => array(
'name' => 'Search',
'required' => true,
'title' => 'Search'
)
)
);
public function collectData() {
$header = array(
'Authorization: Bearer ' . $this->getAPIKey()
);
if(!empty($this->getInput('u'))) {
$postData = getContents(self::URI . 'api/v2/users/~' . urlencode($this->getInput('u')) . '/posts', $header) or
returnServerError('Unable to query Ello API.');
} else {
$postData = getContents(self::URI . 'api/v2/posts?terms=' . urlencode($this->getInput('s')), $header) or
returnServerError('Unable to query Ello API.');
}
$postData = json_decode($postData);
$count = 0;
foreach($postData->posts as $post) {
$item = array();
$item['author'] = $this->getUsername($post, $postData);
$item['timestamp'] = strtotime($post->created_at);
$item['title'] = $this->findText($post->summary);
$item['content'] = $this->getPostContent($post->body);
$item['enclosures'] = $this->getEnclosures($post, $postData);
$content = $post->body;
$this->items[] = $item;
$count += 1;
}
}
public function findText($path) {
foreach($path as $summaryElement) {
if($summaryElement->kind == 'text') {
return $summaryElement->data;
}
}
return '';
}
public function getPostContent($path) {
$content = '';
foreach($path as $summaryElement) {
if($summaryElement->kind == 'text') {
$content .= $summaryElement->data;
} elseif ($summaryElement->kind == 'image') {
$alt = '';
if(property_exists($summaryElement->data, 'alt')) {
$alt = $summaryElement->data->alt;
}
$content .= '<img src="' . $summaryElement->data->url . '" alt="' . $alt . '" />';
}
}
return $content;
}
public function getEnclosures($post, $postData) {
$assets = [];
foreach($post->links->assets as $asset) {
foreach($postData->linked->assets as $assetLink) {
if($asset == $assetLink->id) {
$assets[] = $assetLink->attachment->original->url;
break;
}
}
}
return $assets;
}
public function getUsername($post, $postData) {
foreach($postData->linked->users as $user) {
if($user->id == $post->links->author->id) {
return $user->username;
}
}
}
public function getAPIKey() {
$cache = Cache::create('FileCache');
$cache->setPath(CACHE_DIR);
$cache->setParameters(['key']);
$key = $cache->loadData();
if($key == null) {
$keyInfo = getContents(self::URI . 'api/webapp-token') or
returnServerError('Unable to get token.');
$key = json_decode($keyInfo)->token->access_token;
$cache->saveData($key);
}
return $key;
}
public function getName(){
if(!is_null($this->getInput('u'))) {
return $this->getInput('u') . ' - Ello Bridge';
}
return parent::getName();
}
}

View File

@@ -164,6 +164,12 @@ EOD;
}
//No captcha? We can carry on retrieving page contents :)
//First, we check wether the page is public or not
$loginForm = $html->find('._585r', 0);
if($loginForm != null) {
returnServerError('You must be logged in to view this page. This is not supported by RSS-Bridge.');
}
$element = $html
->find('#pagelet_timeline_main_column')[0]
->children(0)

View File

@@ -11,60 +11,38 @@ class InstagramBridge extends BridgeAbstract {
'u' => array(
'name' => 'username',
'required' => true
),
'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
),
)
),
'global' => array(
'media_type' => array(
'name' => 'Media type',
'type' => 'list',
'required' => false,
'values' => array(
'Both' => 'all',
'All' => 'all',
'Story' => 'story',
'Video' => 'video',
'Picture' => 'picture'
'Picture' => 'picture',
),
'defaultValue' => 'all'
)
)
);
public function collectData(){
$html = getSimpleHTMLDOM($this->getURI())
or returnServerError('Could not request Instagram.');
$innertext = null;
foreach($html->find('script') as $script) {
if('' === $script->innertext) {
continue;
}
$pos = strpos(trim($script->innertext), 'window._sharedData');
if(0 !== $pos) {
continue;
}
$innertext = $script->innertext;
break;
if(!is_null($this->getInput('h')) && $this->getInput('media_type') == 'story') {
returnClientError('Stories are not supported for hashtags!');
}
$json = trim(substr($innertext, $pos + 18), ' =;');
$data = json_decode($json);
$data = $this->getInstagramJSON($this->getURI());
if(!is_null($this->getInput('u'))) {
$userMedia = $data->entry_data->ProfilePage[0]->graphql->user->edge_owner_to_timeline_media->edges;
@@ -74,32 +52,83 @@ class InstagramBridge extends BridgeAbstract {
foreach($userMedia as $media) {
$media = $media->node;
// Check media type
switch($this->getInput('media_type')) {
case 'all': break;
case 'video':
if($media->is_video === false) continue 2;
break;
case 'picture':
if($media->is_video === true) continue 2;
break;
default: break;
if(!is_null($this->getInput('u'))) {
switch($this->getInput('media_type')) {
case 'all': break;
case 'video':
if($media->__typename != 'GraphVideo') continue 2;
break;
case 'picture':
if($media->__typename != 'GraphImage') continue 2;
break;
case 'story':
if($media->__typename != 'GraphSidecar') continue 2;
break;
default: break;
}
} else {
if($this->getInput('media_type') == 'video' && !$media->is_video) continue;
}
$item = array();
$item['uri'] = self::URI . 'p/' . $media->shortcode . '/';
$item['content'] = '<img src="' . htmlentities($media->display_url) . '" />';
if (isset($media->edge_media_to_caption->edges[0]->node->text)) {
$item['title'] = $media->edge_media_to_caption->edges[0]->node->text;
} else {
$item['title'] = basename($media->display_url);
}
if(!is_null($this->getInput('u')) && $media->__typename == 'GraphSidecar') {
$data = $this->getInstagramStory($item['uri']);
$item['content'] = $data[0];
$item['enclosures'] = $data[1];
} else {
$item['content'] = '<img src="' . htmlentities($media->display_url) . '" alt="'. $item["title"] . '" />';
$item['enclosures'] = array($media->display_url);
}
$item['timestamp'] = $media->taken_at_timestamp;
$item['enclosures'] = array($media->display_url);
$this->items[] = $item;
}
}
protected function getInstagramStory($uri) {
$data = $this->getInstagramJSON($uri);
$mediaInfo = $data->entry_data->PostPage[0]->graphql->shortcode_media;
//Process the first element, that isn't in the node graph
$caption = $mediaInfo->edge_media_to_caption->edges[0]->node->text;
$enclosures = [$mediaInfo->display_url];
$content = '<img src="' . htmlentities($mediaInfo->display_url) . '" alt="'. $caption . '" />';
foreach($mediaInfo->edge_sidecar_to_children->edges as $media) {
$content .= '<img src="' . htmlentities($media->node->display_url) . '" alt="'. $caption . '" />';
$enclosures[] = $media->node->display_url;
}
return [$content, $enclosures];
}
protected function getInstagramJSON($uri) {
$html = getContents($uri)
or returnServerError('Could not request Instagram.');
$scriptRegex = '/window\._sharedData = (.*);<\/script>/';
preg_match($scriptRegex, $html, $matches, PREG_OFFSET_CAPTURE, 0);
return json_decode($matches[1][0]);
}
public function getName(){
if(!is_null($this->getInput('u'))) {
return $this->getInput('u') . ' - Instagram Bridge';

View File

@@ -102,10 +102,20 @@ class VkBridge extends BridgeAbstract
// 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;
if (strpos($article->getAttribute('class'), "article_snippet_mini") !== false) {
$article_title_selector = "div.article_snippet_mini_title";
$article_author_selector = "div.article_snippet_mini_info > .mem_link,
div.article_snippet_mini_info > .group_link";
$article_thumb_selector = "div.article_snippet_mini_thumb";
} else {
$article_title_selector = "div.article_snippet__title";
$article_author_selector = "div.article_snippet__author";
$article_thumb_selector = "div.article_snippet__image";
}
$article_title = $article->find($article_title_selector, 0)->innertext;
$article_author = $article->find($article_author_selector, 0)->innertext;
$article_link = self::URI . ltrim($article->getAttribute('href'), '/');
$article_img_element_style = $article->find("div.article_snippet__image", 0)->getAttribute('style');
$article_img_element_style = $article->find($article_thumb_selector, 0)->getAttribute('style');
preg_match('/background-image: url\((.*)\)/', $article_img_element_style, $matches);
if (count($matches) > 0) {
$content_suffix .= "<br><img src='" . $matches[1] . "'>";
@@ -123,6 +133,16 @@ class VkBridge extends BridgeAbstract
$video->outertext = '';
}
// get all other videos
foreach($post->find('a.page_post_thumb_video') as $a) {
$video_title = $a->getAttribute('aria-label');
$temp = explode(" ", $video_title, 2);
if (count($temp) > 1) $video_title = $temp[1];
$video_link = self::URI . ltrim( $a->getAttribute('href'), '/' );
$content_suffix .= "<br>Video: <a href='$video_link'>$video_title</a>";
$a->outertext = '';
}
// get all photos
foreach($post->find('div.wall_text > a.page_post_thumb_wrap') as $a) {
$result = $this->getPhoto($a);
@@ -179,6 +199,16 @@ class VkBridge extends BridgeAbstract
$div->outertext = '';
}
// get polls
foreach($post->find('div.page_media_poll_wrap') as $div) {
$poll_title = $div->find('.page_media_poll_title', 0)->innertext;
$content_suffix .= "<br>Poll: $poll_title";
foreach($div->find('div.page_poll_text') as $poll_stat_title) {
$content_suffix .= "<br>- " . $poll_stat_title->innertext;
}
$div->outertext = '';
}
// get sign
$post_author = $pageName;
foreach($post->find('a.wall_signed_by') as $a) {
@@ -247,7 +277,13 @@ class VkBridge extends BridgeAbstract
$original = '';
foreach(array('y_', 'z_', 'w_') as $key) {
if (!isset($data['temp'][$key])) continue;
$original = $data['temp']['base'] . $data['temp'][$key][0] . ".jpg";
if (!isset($data['temp'][$key][0])) continue;
if (substr($data['temp'][$key][0], 0, 4) == "http") {
$base = "";
} else {
$base = $data['temp']['base'];
}
$original = $base . $data['temp'][$key][0] . ".jpg";
}
if ($original) {

View File

@@ -1,16 +1,12 @@
<?php
class WorldOfTanksBridge extends BridgeAbstract {
class WorldOfTanksBridge extends FeedExpander {
const MAINTAINER = 'mitsukarenai';
const MAINTAINER = 'Riduidel';
const NAME = 'World of Tanks';
const URI = 'http://worldoftanks.eu/';
const DESCRIPTION = 'News about the tank slaughter game.';
const PARAMETERS = array( array(
'category' => array(
// TODO: should be a list
'name' => 'nom de la catégorie'
),
'lang' => array(
'name' => 'Langue',
'type' => 'list',
@@ -26,47 +22,31 @@ class WorldOfTanksBridge extends BridgeAbstract {
)
));
private $title = '';
public function collectData() {
$this->collectExpandableDatas(sprintf('https://worldoftanks.eu/%s/rss/news/', $this->getInput('lang')));
}
public function getURI(){
if(!is_null($this->getInput('lang'))) {
$lang = $this->getInput('lang');
$uri = self::URI . $lang . '/news/';
if(!empty($this->getInput('category'))) {
$uri .= 'pc-browser/' . $this->getInput('category') . '/';
}
return $uri;
protected function parseItem($newsItem){
$item = parent::parseItem($newsItem);
$item['content'] = $this->loadFullArticle($item['uri']);
return $item;
}
/**
* Loads the full article and returns the contents
* @param $uri The article URI
* @return The article content
*/
private function loadFullArticle($uri){
$html = getSimpleHTMLDOMCached($uri);
$content = $html->find('article', 0);
// Remove the scripts, please
foreach($content->find('script') as $script) {
$script->outertext = '';
}
return parent::getURI();
}
public function getName(){
return $this->title ?: parent::getName();
}
public function collectData(){
$html = getSimpleHTMLDOM($this->getURI())
or returnServerError('Could not request ' . $this->getURI());
debugMessage("loaded HTML from " . $this->getURI());
// customize name
$this->title = $html->find('title', 0)->innertext;
foreach($html->find('.b-imgblock_ico') as $infoLink) {
$this->parseLine($infoLink);
}
}
private function parseLine($infoLink){
$item = array();
$item['uri'] = self::URI . $infoLink->href;
// now load that uri from cache
debugMessage('loading page ' . $item['uri']);
$articlePage = getSimpleHTMLDOMCached($item['uri']);
$content = $articlePage->find('.l-content', 0);
defaultLinkTo($content, self::URI);
$item['title'] = $content->find('h1', 0)->innertext;
$item['content'] = $content->find('.b-content', 0)->innertext;
$item['timestamp'] = $content->find('.b-statistic_time', 0)->getAttribute("data-timestamp");
$this->items[] = $item;
return $content->innertext;
}
}

View File

@@ -105,7 +105,10 @@ class YGGTorrentBridge extends BridgeAbstract {
or returnServerError("Unable to query Yggtorrent !");
$count = 0;
foreach($html->find(".results", 0)->find("tr") as $row) {
$results = $html->find(".results", 0);
if(!$results) return;
foreach($results->find("tr") as $row) {
$count++;
if($count == 1) continue;
if($count == 12) break;
@@ -118,6 +121,7 @@ class YGGTorrentBridge extends BridgeAbstract {
$item["seeders"] = $row->find("td", 7)->plaintext;
$item["leechers"] = $row->find("td", 8)->plaintext;
$item["size"] = $row->find("td", 5)->plaintext;
$this->items[] = $item;
}
@@ -127,9 +131,10 @@ class YGGTorrentBridge extends BridgeAbstract {
//For weird reason, the link we get can be invalid, we fix it.
$url_full = explode("/", $url);
$url_full[4] = urlencode($url_full[4]);
$url_full[5] = urlencode($url_full[5]);
$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);

View File

@@ -8,7 +8,9 @@ class FileCache implements CacheInterface {
protected $param;
public function loadData(){
return unserialize(file_get_contents($this->getCacheFile()));
if(file_exists($this->getCacheFile())) {
return unserialize(file_get_contents($this->getCacheFile()));
}
}
public function saveData($datas){

27
config.default.ini.php Normal file
View File

@@ -0,0 +1,27 @@
; <?php exit; ?> DO NOT REMOVE THIS LINE
; This file contains the default settings for RSS-Bridge. Do not change this
; file, it will be replaced on the next update of RSS-Bridge! You can specify
; your own configuration in 'config.ini.php' (copy this file).
[cache]
; Allow users to specify custom timeout for specific requests.
; true = enabled
; false = disabled (default)
custom_timeout = false
[proxy]
; Sets the proxy url (i.e. "tcp://192.168.0.0:32")
; "" = Proxy disabled (default)
url = ""
; Sets the proxy name that is shown on the bridge instead of the proxy url.
; "" = Show proxy url
name = "Hidden proxy name"
; Allow users to disable proxy usage for specific requests.
; true = enabled
; false = disabled (default)
by_bridge = false

View File

@@ -15,8 +15,8 @@ class AtomFormat extends FormatAbstract{
$extraInfos = $this->getExtraInfos();
$title = $this->xml_encode($extraInfos['name']);
$uri = !empty($extraInfos['uri']) ? $extraInfos['uri'] : 'https://github.com/sebsauvage/rss-bridge';
$icon = $this->xml_encode('http://icons.better-idea.org/icon?url='. $uri .'&size=64');
$uri = !empty($extraInfos['uri']) ? $extraInfos['uri'] : 'https://github.com/RSS-Bridge/rss-bridge';
$icon = $this->xml_encode($uri .'/favicon.ico');
$uri = $this->xml_encode($uri);
$entries = '';

View File

@@ -18,10 +18,10 @@ class MrssFormat extends FormatAbstract {
if(!empty($extraInfos['uri'])) {
$uri = $this->xml_encode($extraInfos['uri']);
} else {
$uri = 'https://github.com/sebsauvage/rss-bridge';
$uri = 'https://github.com/RSS-Bridge/rss-bridge';
}
$icon = $this->xml_encode('http://icons.better-idea.org/icon?url='. $uri .'&size=64');
$icon = $this->xml_encode($uri .'/favicon.ico');
$items = '';
foreach($this->getItems() as $item) {

View File

@@ -10,19 +10,47 @@ TODO :
- implement header('X-Cached-Version: '.date(DATE_ATOM, filemtime($cachefile)));
*/
if(!file_exists('config.default.ini.php'))
die('The default configuration file "config.default.ini.php" is missing!');
$config = parse_ini_file('config.default.ini.php', true, INI_SCANNER_TYPED);
if(file_exists('config.ini.php')) {
// Replace default configuration with custom settings
foreach(parse_ini_file('config.ini.php', true, INI_SCANNER_TYPED) as $header => $section) {
foreach($section as $key => $value) {
// Skip unknown sections and keys
if(array_key_exists($header, $config) && array_key_exists($key, $config[$header])) {
$config[$header][$key] = $value;
}
}
}
}
if(!is_string($config['proxy']['url']))
die('Parameter [proxy] => "url" is not a valid string! Please check "config.ini.php"!');
if(!empty($config['proxy']['url']))
define('PROXY_URL', $config['proxy']['url']);
if(!is_bool($config['proxy']['by_bridge']))
die('Parameter [proxy] => "by_bridge" is not a valid Boolean! Please check "config.ini.php"!');
define('PROXY_BYBRIDGE', $config['proxy']['by_bridge']);
if(!is_string($config['proxy']['name']))
die('Parameter [proxy] => "name" is not a valid string! Please check "config.ini.php"!');
define('PROXY_NAME', $config['proxy']['name']);
if(!is_bool($config['cache']['custom_timeout']))
die('Parameter [cache] => "custom_timeout" is not a valid Boolean! Please check "config.ini.php"!');
define('CUSTOM_CACHE_TIMEOUT', $config['cache']['custom_timeout']);
// Defines the minimum required PHP version for RSS-Bridge
define('PHP_VERSION_REQUIRED', '5.6.0');
//define('PROXY_URL', 'tcp://192.168.0.0:28');
// Set to true if you allow users to disable proxy usage for specific bridges
define('PROXY_BYBRIDGE', false);
// Comment this line or keep PROXY_NAME empty to display PROXY_URL instead
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');
error_reporting(0);
@@ -303,7 +331,7 @@ EOD;
echo $inactiveBridges;
?>
<section class="footer">
<a href="https://github.com/RSS-Bridge/rss-bridge">RSS-Bridge 2018-04-20 ~ Public Domain</a><br />
<a href="https://github.com/RSS-Bridge/rss-bridge">RSS-Bridge 2018-06-10 ~ Public Domain</a><br />
<?= $activeFoundBridgeCount; ?>/<?= count($bridgeList) ?> active bridges. <br />
<?php
if($activeFoundBridgeCount !== count($bridgeList)) {

View File

@@ -22,10 +22,12 @@ function getContents($url, $header = array(), $opts = array()){
}
$content = curl_exec($ch);
$curlError = curl_error($ch);
$curlErrno = curl_errno($ch);
curl_close($ch);
if($content === false)
debugMessage('Cant\'t download ' . $url);
debugMessage('Cant\'t download ' . $url . ' cUrl error: ' . $curlError . ' (' . $curlErrno . ')');
return $content;
}