mirror of
https://github.com/RSS-Bridge/rss-bridge.git
synced 2025-08-21 23:55:56 +02:00
Compare commits
290 Commits
v0.2
...
2018-04-06
Author | SHA1 | Date | |
---|---|---|---|
|
178177e787 | ||
|
1cb83ccea3 | ||
|
c899399569 | ||
|
0f93370e92 | ||
|
45c3dcb636 | ||
|
ecfc220b10 | ||
|
4b3efed7ec | ||
|
bc28c5da8e | ||
|
5bd9c1611d | ||
|
6caca4946b | ||
|
ee78e7613f | ||
|
2df2623430 | ||
|
de5f850cdb | ||
|
ac6847045c | ||
|
df6da837dc | ||
|
41b7984a4e | ||
|
38c7e0272e | ||
|
29c690dbcd | ||
|
8ba817478b | ||
|
cacbe90102 | ||
|
cb91cd5d2f | ||
|
52dfa3fe76 | ||
|
29a1c7ac09 | ||
|
6eea51eeeb | ||
|
2149af0e74 | ||
|
142a647b7a | ||
|
6e916ddd35 | ||
|
159b00145d | ||
|
26ce16baa2 | ||
|
0622fe142b | ||
|
4805b52d42 | ||
|
962617086e | ||
|
4f6277b6b5 | ||
|
5aaab9eb8c | ||
|
ef402bb5c3 | ||
|
85ac9001d6 | ||
|
7939bffcdd | ||
|
bb58aa8e31 | ||
|
1d35149191 | ||
|
be03764029 | ||
|
a07874d468 | ||
|
90d7ae8776 | ||
|
93e0562353 | ||
|
4c5d547d9c | ||
|
9a3a64010f | ||
|
e59a6f4c9e | ||
|
1506e68587 | ||
|
671cba4f68 | ||
|
374eb8f4bf | ||
|
60f7a2b3e4 | ||
|
7744172c63 | ||
|
5a763aee8d | ||
|
c14b2c6905 | ||
|
0871376922 | ||
|
c5fe9a6dc0 | ||
|
fbbcd02384 | ||
|
d34987f9c1 | ||
|
9e0565c655 | ||
|
443081c90b | ||
|
03fc09e3c6 | ||
|
45323c2b2f | ||
|
67ee73782c | ||
|
2bb9a29ddc | ||
|
5cbd363597 | ||
|
aa6ded0ea4 | ||
|
3c61dc2b57 | ||
|
3e528ddccf | ||
|
cba65d6d08 | ||
|
8d418611a2 | ||
|
98b0f0f8ba | ||
|
6f66e6d9be | ||
|
8b06299bad | ||
|
5a99981827 | ||
|
e30ad3feb4 | ||
|
77657a9154 | ||
|
3059b1ea80 | ||
|
4037c34393 | ||
|
e671a2ad02 | ||
|
1ea091f215 | ||
|
87fa4ae3ac | ||
|
d7a1dca004 | ||
|
fe48340327 | ||
|
b4c6aa41a7 | ||
|
1696aee212 | ||
|
585379d47a | ||
|
2595b5d7d8 | ||
|
f858adc884 | ||
|
44e135ce1e | ||
|
9a9ce30b16 | ||
|
0e2b80d5d7 | ||
|
1b1ab6a66e | ||
|
0284e9d488 | ||
|
f91309c7e4 | ||
|
cd012e115b | ||
|
df9e3968dc | ||
|
c237eaa254 | ||
|
f757d7d1a5 | ||
|
4fb1366aaf | ||
|
8166e33e7f | ||
|
ff3b1c9eb2 | ||
|
4924769549 | ||
|
e4fa963bdf | ||
|
54e8bb2228 | ||
|
99e7e7876e | ||
|
62c190d841 | ||
|
84d2c02a09 | ||
|
fc0ae42450 | ||
|
9599f921a5 | ||
|
e125e9aba1 | ||
|
55a77c734d | ||
|
ccd8af09b9 | ||
|
f2d02a4187 | ||
|
f19d34a5a1 | ||
|
f1534c91e2 | ||
|
cbda060b86 | ||
|
f7265ca77b | ||
|
629a4c4481 | ||
|
950ae2cc05 | ||
|
873a91259f | ||
|
c7ec50373a | ||
|
c986ff9116 | ||
|
485b465a24 | ||
|
a4b9611e66 | ||
|
38b56bf23a | ||
|
6e4bc341b7 | ||
|
fa2df09b1b | ||
|
7dda088b3f | ||
|
f6f3a213ef | ||
|
1faa91ef0f | ||
|
5caca62677 | ||
|
d7ff8b9ac7 | ||
|
ab46af9719 | ||
|
06babeb644 | ||
|
341010b391 | ||
|
995d78fa5a | ||
|
781e4f1908 | ||
|
ae59b20c0c | ||
|
d81b61ccfa | ||
|
9c78362fd7 | ||
|
18c6f0126f | ||
|
d5f47efcea | ||
|
601f61f063 | ||
|
8ed4812e00 | ||
|
f38db4d79e | ||
|
88d1068406 | ||
|
627038e2fa | ||
|
5b541e380a | ||
|
c375ddd6ab | ||
|
44c3110db0 | ||
|
120e74c1b4 | ||
|
890ba69116 | ||
|
d6da2ce406 | ||
|
0eb5711a68 | ||
|
a4ef42c2e9 | ||
|
28331e7cd6 | ||
|
6eadc6ca6f | ||
|
638d173b70 | ||
|
a9535797e6 | ||
|
fc9084eb17 | ||
|
e221358ead | ||
|
2500d0df93 | ||
|
4124c707d4 | ||
|
8e84b52152 | ||
|
f3b6b264d3 | ||
|
360f9da072 | ||
|
e3b335b9ff | ||
|
9acd30a5c5 | ||
|
3276d4e3d5 | ||
|
88586381e7 | ||
|
ebe897f120 | ||
|
1a4c3f4418 | ||
|
2ac0469750 | ||
|
c0181d8d41 | ||
|
ea3073e27f | ||
|
20ea75994d | ||
|
a84c245fa0 | ||
|
b48a44c979 | ||
|
c6ce453c47 | ||
|
bd92392921 | ||
|
59025d96bc | ||
|
155c0ac6f0 | ||
|
596b9143a8 | ||
|
a2108c784f | ||
|
c803396d7e | ||
|
ac518ca297 | ||
|
1763a1518c | ||
|
2dda74dfe7 | ||
|
b1c2a69102 | ||
|
bf7ce98719 | ||
|
8b2fdb3937 | ||
|
5d41a74067 | ||
|
100f3cd56d | ||
|
8f3c56b184 | ||
|
16bdf6b204 | ||
|
cf7da1d41c | ||
|
bb8e7495d8 | ||
|
5de03d6b9f | ||
|
1d26c7f1c3 | ||
|
790bd17d41 | ||
|
1dcef02f27 | ||
|
801ea837c9 | ||
|
9124ed640e | ||
|
6d1e8af982 | ||
|
512a4f292b | ||
|
c4169f1579 | ||
|
d93d491d8e | ||
|
c44fb25845 | ||
|
761c66d813 | ||
|
ff83410534 | ||
|
d8f5aa3c79 | ||
|
23430f1c07 | ||
|
0c3e58258c | ||
|
b4f1dc35a1 | ||
|
6f24858124 | ||
|
22a7666d2b | ||
|
04b885264d | ||
|
37b5df8985 | ||
|
f16835c223 | ||
|
7ad8693b5f | ||
|
0f25684e65 | ||
|
9bf74b2715 | ||
|
d91c25cff1 | ||
|
6ddcedb53f | ||
|
a1764a9fe2 | ||
|
1028e538ab | ||
|
49cc0661ad | ||
|
3109694b1c | ||
|
aa0a84bc26 | ||
|
eb22f86f44 | ||
|
cf909ef3a1 | ||
|
94d2ebec0a | ||
|
44c7cbe2d7 | ||
|
5b4ba621ee | ||
|
9c1bedb33f | ||
|
2fd60c68b0 | ||
|
670d8f18cb | ||
|
41714b4c40 | ||
|
a4f4447c5e | ||
|
3d984e8762 | ||
|
3a6ccc4c29 | ||
|
f45405950d | ||
|
0e5cf0d14e | ||
|
9405dc6c4b | ||
|
d0c9397613 | ||
|
5ad3198d71 | ||
|
83b5bbcc37 | ||
|
f694023f7d | ||
|
61b9c3eb48 | ||
|
d4fb02b0d0 | ||
|
95b99d42a4 | ||
|
271c71d0ac | ||
|
1e0cef8f7f | ||
|
8b52b3858e | ||
|
4a1e5245b3 | ||
|
cad78be37b | ||
|
a5b0e2a24f | ||
|
4972cec951 | ||
|
f09e8e1139 | ||
|
64fa134c40 | ||
|
d9030bfb97 | ||
|
278d6a0ec2 | ||
|
8bb002c7b6 | ||
|
b4e6c0d973 | ||
|
1ef7e40ecd | ||
|
00403214ce | ||
|
9c65c7b9e1 | ||
|
877465d508 | ||
|
35415004b9 | ||
|
e908fe648b | ||
|
3f503c4356 | ||
|
f4aa3b39e8 | ||
|
c702a0e69f | ||
|
5edba3a1aa | ||
|
8d41718553 | ||
|
72f40fbd75 | ||
|
14c689e7a3 | ||
|
84bc9d2da6 | ||
|
42cbc2e889 | ||
|
3a2cb9ea1e | ||
|
4f4fb11789 | ||
|
28e813620f | ||
|
fdf98041e3 | ||
|
29e64f77aa | ||
|
4dfbc16a5b | ||
|
af572341b3 | ||
|
51e9298a2b | ||
|
6df657179f | ||
|
2ff422d312 | ||
|
1b3efce64d | ||
|
750812c512 |
15
.travis.yml
15
.travis.yml
@@ -1,11 +1,9 @@
|
||||
dist: trusty
|
||||
sudo: false
|
||||
language: php
|
||||
php:
|
||||
- '5.6'
|
||||
- '7.0'
|
||||
- hhvm
|
||||
- nightly
|
||||
|
||||
install:
|
||||
- pear channel-update pear.php.net
|
||||
- pear install PHP_CodeSniffer
|
||||
|
||||
script:
|
||||
@@ -14,6 +12,13 @@ script:
|
||||
|
||||
matrix:
|
||||
fast_finish: true
|
||||
|
||||
include:
|
||||
- php: 5.6
|
||||
- php: 7.0
|
||||
- php: hhvm
|
||||
- php: nightly
|
||||
|
||||
allow_failures:
|
||||
- php: hhvm
|
||||
- php: nightly
|
110
CHANGELOG.md
110
CHANGELOG.md
@@ -1,11 +1,105 @@
|
||||
rss-bridge Changelog
|
||||
===
|
||||
|
||||
Alpha 0.1
|
||||
===
|
||||
* First tagged version.
|
||||
* Includes refactoring.
|
||||
* Unstable.
|
||||
RSS-Bridge 2017-08-19
|
||||
==
|
||||
|
||||
## General changes
|
||||
* whitelist: Do case-insensitive whitelist matching
|
||||
* [FeedExpander] Fix Serialization of 'SimpleXMLElement' is not allowed
|
||||
* [FeedExpander] Remove whitespace from source content
|
||||
* [index] Add GET parameter 'q' for search queries
|
||||
- **Example**: You can now add `&q=Twitter` to load into the search field
|
||||
* [index] Check permissions for cache folder and whitelist file
|
||||
* [index] Show bridge options when loading with URL fragment
|
||||
- **Example**: You can now add `#bridge-Twitter` to load the card with all
|
||||
parameters visible
|
||||
* [style] Center search cursor and hide placeholder
|
||||
* [validation] Fix error on undefined optional numeric value
|
||||
|
||||
## Modified bridges
|
||||
* [DanbooruBridge] Allow descendant classes to override tag collection
|
||||
* [DribbbleBridge] Add dribble bridge listing last dribble popular shots (#558)
|
||||
* [FacebookBridge] Fix & in URLs
|
||||
* [GelbooruBridge] Fix bridge not getting tags correctly
|
||||
* [GoComicsBridge] Fix for page structure changes (#568)
|
||||
* [LeBonCoinBridge] Fix bridge is marked executable
|
||||
* [LWNprevBridge] Fix everchanging url
|
||||
* [YoutubeBridge] Fix error on certain keywords
|
||||
* [YoutubeBridge] Fix issues loading playlists
|
||||
|
||||
## Removed bridges
|
||||
* VineBridge
|
||||
|
||||
RSS-Bridge 2017-08-03
|
||||
==
|
||||
|
||||
## Important changes
|
||||
* RSS-Bridge now has [contribution guidelines](CONTRIBUTING.md)
|
||||
* [phpcs rules](phpcs.xml) follow the [contribution guidelines](CONTRIBUTING.md)
|
||||
|
||||
## General changes
|
||||
* Added a search bar to make searching for bridges easier
|
||||
* Added user friendly error page for when a bridge fails
|
||||
* Added caching of extraInfos (name, uri)
|
||||
* Added an indicator to warn for bridges using HTTP instead of HTTPS
|
||||
* Various bug fixes and improvements
|
||||
|
||||
## Modified bridges
|
||||
* AllocineFRBridge] Update Faux Raccord link
|
||||
* [DanbooruBridge] Fix broken URI
|
||||
* [DuckDuckGoBridge] Disable DuckDuckGo redirects so that the links returned are correct.
|
||||
* [FacebookBridge] Add option to hide posts with facebook videos
|
||||
* [FacebookBridge] Add requester languages to HTTP header
|
||||
* [FacebookBridge] Handle summary posts
|
||||
* [FacebookBridge] Replace 'novideo' with 'media_type'
|
||||
* [FilterBridge] Initial implementation of basic title permit and block
|
||||
* [FlickrTagBridge] Fix and improve bridge by using the FlickrExploreBridge approach
|
||||
* [GooglePlusPostBridge] Autofix user names
|
||||
* [GooglePlusPostBridge] Fix bridge implementation
|
||||
* [GooglePlusPostBridge] Fix content loading
|
||||
* [InstagramBridge] Add option to filter for videos and pictures
|
||||
* [LWNprevBridge] full rewrite
|
||||
* [MangareaderBridge] Fix double forward slashes
|
||||
* [NasaApodBridge] Use HTTPS instead of HTTP
|
||||
* [PinterestBridge] Fix checkbox not working
|
||||
* [PinterestBridge] Fix implementation after DOM changes
|
||||
* [RTBFBridge] Update URI
|
||||
* [SexactuBridge] Fix URI and timestamp
|
||||
* [SexactuBridge] Use most modern version of bridge api and cached pages (#504)
|
||||
* [ShanaprojectBridge] Don't throw error if timestamp is missing
|
||||
* [TwitterBridge] Add option to hide retweets
|
||||
* [TwitterBridge] Avoid empty content caused by new login policy
|
||||
* [TwitterBridge] Fix double slashes in URI
|
||||
* [TwitterBridge] Fix missing spaces
|
||||
* [TwitterBridge] Fix title includes anchors in plaintext format
|
||||
* [TwitterBridge] ignore promoted tweets
|
||||
* [TwitterBridge] Optimize returned image sizes
|
||||
* [TwitterBridge] Show quotes and pictures
|
||||
* [WebfailBridge] Properly handle gifs (DOM changed)
|
||||
* [YoutubeBridge] Improve readability of feed contents
|
||||
* [YoutubeBridge] Improve URL handling in video descriptions
|
||||
|
||||
## New bridges
|
||||
* AmazonBridge
|
||||
* DiceBridge
|
||||
* EtsyBridge
|
||||
* FB2Bridge
|
||||
* FilterBridge
|
||||
* FlickrBridge
|
||||
* GithubSearchBridge
|
||||
* GoComicsBridge
|
||||
* KATBridge
|
||||
* KernelBugTrackerBridge
|
||||
* MixCloudBridge
|
||||
* MoinMoinBridge
|
||||
* RainbowSixSiegeBridge
|
||||
* SteamBridge
|
||||
* TheTVDBBridge
|
||||
* Torrent9Bridge
|
||||
* UsbekEtRicaBridge
|
||||
* WikiLeaksBridge
|
||||
* WordPressPluginUpdateBridge
|
||||
|
||||
Alpha 0.2
|
||||
===
|
||||
@@ -161,3 +255,9 @@ Alpha 0.2
|
||||
* YandereBridge
|
||||
* YoutubeBridge
|
||||
* ZDNetBridge
|
||||
|
||||
Alpha 0.1
|
||||
===
|
||||
* First tagged version.
|
||||
* Includes refactoring.
|
||||
* Unstable.
|
47
CONTRIBUTING.md
Normal file
47
CONTRIBUTING.md
Normal file
@@ -0,0 +1,47 @@
|
||||
### Pull request policy
|
||||
Fix one issue per pull request.
|
||||
Squash commits before opening a pull request.
|
||||
Respect the coding style policy.
|
||||
Name your PR like the following :
|
||||
|
||||
* When correcting a single bridge, use `[BridgeName] Feature`.
|
||||
* When fixing a problem in a specific file, use `[FileName] Feature`.
|
||||
* When fixing a general problem, use `category : feature`.
|
||||
|
||||
Note that all pull-requests should pass the unit tests before they can be merged.
|
||||
|
||||
### Coding style
|
||||
|
||||
Use `camelCase` for variables and methods.
|
||||
Use `UPPERCASE` for constants.
|
||||
Use `PascalCase` for class names. When creating a bridge, your class and PHP file should be named `MyImplementationBridge`.
|
||||
Use tabs for indentation.
|
||||
Add an empty line at the end of your file.
|
||||
|
||||
Use `''` to encapsulate strings, including in arrays.
|
||||
Prefer lines shorter than 80 chars, no line longer than 120 chars.
|
||||
PHP constants should be in lower case (`true, false, null`...)
|
||||
|
||||
|
||||
* Add spaces between the logical operator and your expressions (not needed for the `!` operator).
|
||||
* Use `||` and `&&` instead of `or` and `and`.
|
||||
* Add space between your condition and the opening bracket/closing bracket.
|
||||
* Don't put a space between `if` and your bracket.
|
||||
* Use `elseif` instead of `else if`.
|
||||
* Add new lines in your conditions if they are containing more than one line.
|
||||
* Example :
|
||||
|
||||
```PHP
|
||||
if($a == true && $b) {
|
||||
print($a);
|
||||
} else if(!$b) {
|
||||
|
||||
$a = !$a;
|
||||
$b = $b >> $a;
|
||||
print($b);
|
||||
|
||||
} else {
|
||||
print($b);
|
||||
}
|
||||
```
|
||||
|
24
README.md
24
README.md
@@ -1,29 +1,29 @@
|
||||
rss-bridge
|
||||
===
|
||||
[](UNLICENSE)
|
||||
[](UNLICENSE) [](https://travis-ci.org/RSS-Bridge/rss-bridge)
|
||||
|
||||
rss-bridge is a PHP project capable of generating ATOM feeds for websites which don't have one.
|
||||
|
||||
Supported sites/pages (main)
|
||||
===
|
||||
|
||||
* `FlickrExplore` : [Latest interesting images](http://www.flickr.com/explore) from Flickr
|
||||
* `GoogleSearch` : Most recent results from Google Search
|
||||
* `GooglePlus` : Most recent posts of user timeline
|
||||
* `Twitter` : Return keyword/hashtag search or user timeline
|
||||
* `Identi.ca` : Identica user timeline (Should be compatible with other Pump.io instances)
|
||||
* `YouTube` : YouTube user channel, playlist or search
|
||||
* `Bandcamp` : Returns last release from [bandcamp](https://bandcamp.com/) for a tag
|
||||
* `Cryptome` : Returns the most recent documents from [Cryptome.org](http://cryptome.org/)
|
||||
* `DansTonChat`: Most recent quotes from [danstonchat.com](http://danstonchat.com/)
|
||||
* `DuckDuckGo`: Most recent results from [DuckDuckGo.com](https://duckduckgo.com/)
|
||||
* `Facebook` : Returns the latest posts on a page or profile on [Facebook](https://facebook.com/)
|
||||
* `FlickrExplore` : [Latest interesting images](http://www.flickr.com/explore) from Flickr
|
||||
* `GooglePlus` : Most recent posts of user timeline
|
||||
* `GoogleSearch` : Most recent results from Google Search
|
||||
* `Identi.ca` : Identica user timeline (Should be compatible with other Pump.io instances)
|
||||
* `Instagram`: Most recent photos from an Instagram user
|
||||
* `OpenClassrooms`: Lastest tutorials from [fr.openclassrooms.com](http://fr.openclassrooms.com/)
|
||||
* `Pinterest`: Most recent photos from user or search
|
||||
* `ScmbBridge`: Newest stories from [secouchermoinsbete.fr](http://secouchermoinsbete.fr/)
|
||||
* `Wikipedia`: highlighted articles from [Wikipedia](https://wikipedia.org/) in English, German, French or Esperanto
|
||||
* `Bandcamp` : Returns last release from [bandcamp](https://bandcamp.com/) for a tag
|
||||
* `ThePirateBay` : Returns the newest indexed torrents from [The Pirate Bay](https://thepiratebay.se/) with keywords
|
||||
* `Facebook` : Returns the latest posts on a page or profile on [Facebook](https://facebook.com/)
|
||||
* `Twitter` : Return keyword/hashtag search or user timeline
|
||||
* `Wikipedia`: highlighted articles from [Wikipedia](https://wikipedia.org/) in English, German, French or Esperanto
|
||||
* `YouTube` : YouTube user channel, playlist or search
|
||||
|
||||
Plus [many other bridges](bridges/) to enable, thanks to the community
|
||||
|
||||
@@ -32,9 +32,9 @@ Output format
|
||||
Output format can take several forms:
|
||||
|
||||
* `Atom` : ATOM Feed, for use in RSS/Feed readers
|
||||
* `Mrss` : MRSS Feed, for use in RSS/Feed readers
|
||||
* `Json` : Json, for consumption by other applications.
|
||||
* `Html` : Simple html page.
|
||||
* `Json` : Json, for consumption by other applications.
|
||||
* `Mrss` : MRSS Feed, for use in RSS/Feed readers
|
||||
* `Plaintext` : raw text (php object, as returned by print_r)
|
||||
|
||||
Screenshot
|
||||
|
@@ -1,24 +1,41 @@
|
||||
<?php
|
||||
class ABCTabsBridge extends BridgeAbstract {
|
||||
|
||||
const MAINTAINER = "kranack";
|
||||
const NAME = "ABC Tabs Bridge";
|
||||
const URI = "http://www.abc-tabs.com/";
|
||||
const DESCRIPTION = "Returns 22 newest tabs";
|
||||
const MAINTAINER = 'kranack';
|
||||
const NAME = 'ABC Tabs Bridge';
|
||||
const URI = 'https://www.abc-tabs.com/';
|
||||
const DESCRIPTION = 'Returns 22 newest tabs';
|
||||
|
||||
public function collectData(){
|
||||
$html = '';
|
||||
$html = getSimpleHTMLDOM(static::URI.'tablatures/nouveautes.html') or returnClientError('No results for this query.');
|
||||
$html = getSimpleHTMLDOM(static::URI.'tablatures/nouveautes.html')
|
||||
or returnClientError('No results for this query.');
|
||||
|
||||
$table = $html->find('table#myTable', 0)->children(1);
|
||||
|
||||
foreach ($table->find('tr') as $tab)
|
||||
{
|
||||
foreach ($table->find('tr') as $tab) {
|
||||
$item = array();
|
||||
$item['author'] = $tab->find('td', 1)->plaintext . ' - ' . $tab->find('td', 2)->plaintext;
|
||||
$item['title'] = $tab->find('td', 1)->plaintext . ' - ' . $tab->find('td', 2)->plaintext;
|
||||
$item['content'] = 'Le ' . $tab->find('td', 0)->plaintext . '<br> Par: ' . $tab->find('td', 5)->plaintext . '<br> Type: ' . $tab->find('td', 3)->plaintext;
|
||||
$item['id'] = static::URI . $tab->find('td', 2)->find('a', 0)->getAttribute('href');
|
||||
$item['uri'] = static::URI . $tab->find('td', 2)->find('a', 0)->getAttribute('href');
|
||||
$item['author'] = $tab->find('td', 1)->plaintext
|
||||
. ' - '
|
||||
. $tab->find('td', 2)->plaintext;
|
||||
|
||||
$item['title'] = $tab->find('td', 1)->plaintext
|
||||
. ' - '
|
||||
. $tab->find('td', 2)->plaintext;
|
||||
|
||||
$item['content'] = 'Le '
|
||||
. $tab->find('td', 0)->plaintext
|
||||
. '<br> Par: '
|
||||
. $tab->find('td', 5)->plaintext
|
||||
. '<br> Type: '
|
||||
. $tab->find('td', 3)->plaintext;
|
||||
|
||||
$item['id'] = static::URI
|
||||
. $tab->find('td', 2)->find('a', 0)->getAttribute('href');
|
||||
|
||||
$item['uri'] = static::URI
|
||||
. $tab->find('td', 2)->find('a', 0)->getAttribute('href');
|
||||
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
|
@@ -1,11 +1,11 @@
|
||||
<?php
|
||||
class AcrimedBridge extends FeedExpander {
|
||||
|
||||
const MAINTAINER = "qwertygc";
|
||||
const NAME = "Acrimed Bridge";
|
||||
const URI = "http://www.acrimed.org/";
|
||||
const MAINTAINER = 'qwertygc';
|
||||
const NAME = 'Acrimed Bridge';
|
||||
const URI = 'http://www.acrimed.org/';
|
||||
const CACHE_TIMEOUT = 4800; //2hours
|
||||
const DESCRIPTION = "Returns the newest articles.";
|
||||
const DESCRIPTION = 'Returns the newest articles';
|
||||
|
||||
public function collectData(){
|
||||
$this->collectExpandableDatas(static::URI . 'spip.php?page=backend');
|
||||
@@ -16,7 +16,7 @@ class AcrimedBridge extends FeedExpander {
|
||||
|
||||
$articlePage = getSimpleHTMLDOM($newsItem->link);
|
||||
$article = sanitize($articlePage->find('article.article1', 0)->innertext);
|
||||
$article = defaultImageSrcTo($article, static::URI);
|
||||
$article = defaultLinkTo($article, static::URI);
|
||||
$item['content'] = $article;
|
||||
|
||||
return $item;
|
||||
|
@@ -1,12 +1,11 @@
|
||||
<?php
|
||||
class AllocineFRBridge extends BridgeAbstract {
|
||||
|
||||
|
||||
const MAINTAINER = "superbaillot.net";
|
||||
const NAME = "Allo Cine Bridge";
|
||||
const MAINTAINER = 'superbaillot.net';
|
||||
const NAME = 'Allo Cine Bridge';
|
||||
const CACHE_TIMEOUT = 25200; // 7h
|
||||
const URI = "http://www.allocine.fr/";
|
||||
const DESCRIPTION = "Bridge for allocine.fr";
|
||||
const URI = 'http://www.allocine.fr/';
|
||||
const DESCRIPTION = 'Bridge for allocine.fr';
|
||||
const PARAMETERS = array( array(
|
||||
'category' => array(
|
||||
'name' => 'category',
|
||||
@@ -23,9 +22,11 @@ class AllocineFRBridge extends BridgeAbstract{
|
||||
));
|
||||
|
||||
public function getURI(){
|
||||
if(!is_null($this->getInput('category'))) {
|
||||
|
||||
switch($this->getInput('category')) {
|
||||
case 'faux-raccord':
|
||||
$uri = static::URI.'video/programme-12284/saison-27129/';
|
||||
$uri = static::URI . 'video/programme-12284/saison-32180/';
|
||||
break;
|
||||
case 'top-5':
|
||||
$uri = static::URI . 'video/programme-12299/saison-29561/';
|
||||
@@ -38,7 +39,11 @@ class AllocineFRBridge extends BridgeAbstract{
|
||||
return $uri;
|
||||
}
|
||||
|
||||
return parent::getURI();
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
if(!is_null($this->getInput('category'))) {
|
||||
return self::NAME . ' : '
|
||||
.array_search(
|
||||
$this->getInput('category'),
|
||||
@@ -46,27 +51,27 @@ class AllocineFRBridge extends BridgeAbstract{
|
||||
);
|
||||
}
|
||||
|
||||
return parent::getName();
|
||||
}
|
||||
|
||||
public function collectData(){
|
||||
|
||||
$html = getSimpleHTMLDOM($this->getURI())
|
||||
or returnServerError("Could not request ".$this->getURI()." !");
|
||||
or returnServerError('Could not request ' . $this->getURI() . ' !');
|
||||
|
||||
$category = array_search(
|
||||
$this->getInput('category'),
|
||||
self::PARAMETERS[$this->queriedContext]['category']['values']
|
||||
);
|
||||
|
||||
|
||||
foreach($html->find('figure.media-meta-fig') as $element)
|
||||
{
|
||||
foreach($html->find('.media-meta-list figure.media-meta-fig') as $element) {
|
||||
$item = array();
|
||||
|
||||
$title = $element->find('div.titlebar h3.title a', 0);
|
||||
$content = trim($element->innertext);
|
||||
$figCaption = strpos($content, $category);
|
||||
|
||||
if($figCaption !== false)
|
||||
{
|
||||
if($figCaption !== false) {
|
||||
$content = str_replace('src="/', 'src="' . static::URI, $content);
|
||||
$content = str_replace('href="/', 'href="' . static::URI, $content);
|
||||
$content = str_replace('src=\'/', 'src=\'' . static::URI, $content);
|
||||
|
94
bridges/AmazonBridge.php
Normal file
94
bridges/AmazonBridge.php
Normal file
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
class AmazonBridge extends BridgeAbstract {
|
||||
|
||||
const MAINTAINER = 'Alexis CHEMEL';
|
||||
const NAME = 'Amazon';
|
||||
const URI = 'https://www.amazon.com/';
|
||||
const CACHE_TIMEOUT = 3600; // 1h
|
||||
const DESCRIPTION = 'Returns products from Amazon search';
|
||||
|
||||
const PARAMETERS = array(array(
|
||||
'q' => array(
|
||||
'name' => 'Keyword',
|
||||
'required' => true,
|
||||
),
|
||||
'sort' => array(
|
||||
'name' => 'Sort by',
|
||||
'type' => 'list',
|
||||
'required' => false,
|
||||
'values' => array(
|
||||
'Relevance' => 'relevanceblender',
|
||||
'Price: Low to High' => 'price-asc-rank',
|
||||
'Price: High to Low' => 'price-desc-rank',
|
||||
'Average Customer Review' => 'review-rank',
|
||||
'Newest Arrivals' => 'date-desc-rank',
|
||||
),
|
||||
'defaultValue' => 'relevanceblender',
|
||||
),
|
||||
'tld' => array(
|
||||
'name' => 'Country',
|
||||
'type' => 'list',
|
||||
'required' => true,
|
||||
'values' => array(
|
||||
'Australia' => 'com.au',
|
||||
'Brazil' => 'com.br',
|
||||
'Canada' => 'ca',
|
||||
'China' => 'cn',
|
||||
'France' => 'fr',
|
||||
'Germany' => 'de',
|
||||
'India' => 'in',
|
||||
'Italy' => 'it',
|
||||
'Japan' => 'co.jp',
|
||||
'Mexico' => 'com.mx',
|
||||
'Netherlands' => 'nl',
|
||||
'Spain' => 'es',
|
||||
'United Kingdom' => 'co.uk',
|
||||
'United States' => 'com',
|
||||
),
|
||||
'defaultValue' => 'com',
|
||||
),
|
||||
));
|
||||
|
||||
public function getName(){
|
||||
if(!is_null($this->getInput('tld')) && !is_null($this->getInput('q'))) {
|
||||
return 'Amazon.'.$this->getInput('tld').': '.$this->getInput('q');
|
||||
}
|
||||
|
||||
return parent::getName();
|
||||
}
|
||||
|
||||
public function collectData() {
|
||||
|
||||
$uri = 'https://www.amazon.'.$this->getInput('tld').'/';
|
||||
$uri .= 's/?field-keywords='.urlencode($this->getInput('q')).'&sort='.$this->getInput('sort');
|
||||
|
||||
$html = getSimpleHTMLDOM($uri)
|
||||
or returnServerError('Could not request Amazon.');
|
||||
|
||||
foreach($html->find('li.s-result-item') as $element) {
|
||||
|
||||
$item = array();
|
||||
|
||||
// Title
|
||||
$title = $element->find('h2', 0);
|
||||
|
||||
$item['title'] = html_entity_decode($title->innertext, ENT_QUOTES);
|
||||
|
||||
// Url
|
||||
$uri = $title->parent()->getAttribute('href');
|
||||
$uri = substr($uri, 0, strrpos($uri, '/'));
|
||||
|
||||
$item['uri'] = substr($uri, 0, strrpos($uri, '/'));
|
||||
|
||||
// Content
|
||||
$image = $element->find('img', 0);
|
||||
$price = $element->find('span.s-price', 0);
|
||||
$price = ($price) ? $price->innertext : '';
|
||||
|
||||
$item['content'] = '<img src="'.$image->getAttribute('src').'" /><br />'.$price;
|
||||
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
}
|
@@ -48,10 +48,14 @@ class AnimeUltimeBridge extends BridgeAbstract {
|
||||
//Retrieve day and build date information
|
||||
$dateString = $daySection->plaintext;
|
||||
$day = intval(substr($dateString, strpos($dateString, ' ') + 1, 2));
|
||||
$item_date = strtotime(str_pad($day, 2, '0', STR_PAD_LEFT).'-'
|
||||
.substr($requestFilter, 0, 2).'-'
|
||||
$item_date = strtotime(str_pad($day, 2, '0', STR_PAD_LEFT)
|
||||
. '-'
|
||||
. substr($requestFilter, 0, 2)
|
||||
. '-'
|
||||
. substr($requestFilter, 2, 4));
|
||||
$release = $daySection->next_sibling()->next_sibling()->first_child(); //<h3>day</h3><br /><table><tr> <-- useful data in table rows
|
||||
|
||||
//<h3>day</h3><br /><table><tr> <-- useful data in table rows
|
||||
$release = $daySection->next_sibling()->next_sibling()->first_child();
|
||||
|
||||
//Process each release of that day, ignoring first table row: contains table headers
|
||||
while(!is_null($release = $release->next_sibling())) {
|
||||
@@ -61,19 +65,27 @@ class AnimeUltimeBridge extends BridgeAbstract {
|
||||
$item_link_element = $release->find('td', 0)->find('a', 0);
|
||||
$item_uri = self::URI . $item_link_element->href;
|
||||
$item_name = html_entity_decode($item_link_element->plaintext);
|
||||
$item_episode = html_entity_decode(str_pad($release->find('td', 1)->plaintext, 2, '0', STR_PAD_LEFT));
|
||||
$item_episode = html_entity_decode(
|
||||
str_pad(
|
||||
$release->find('td', 1)->plaintext,
|
||||
2,
|
||||
'0',
|
||||
STR_PAD_LEFT
|
||||
)
|
||||
);
|
||||
|
||||
$item_fansub = $release->find('td', 2)->plaintext;
|
||||
$item_type = $release->find('td', 4)->plaintext;
|
||||
|
||||
if(!empty($item_uri)) {
|
||||
|
||||
//Retrieve description from description page and convert relative image src info absolute image src
|
||||
// Retrieve description from description page and
|
||||
// convert relative image src info absolute image src
|
||||
$html_item = getContents($item_uri)
|
||||
or returnServerError('Could not request Anime-Ultime: ' . $item_uri);
|
||||
$item_description = substr(
|
||||
$html_item,
|
||||
strpos($html_item, 'class="principal_contain" align="center">')
|
||||
+ 41
|
||||
strpos($html_item, 'class="principal_contain" align="center">') + 41
|
||||
);
|
||||
$item_description = substr($item_description,
|
||||
0,
|
||||
@@ -108,6 +120,7 @@ class AnimeUltimeBridge extends BridgeAbstract {
|
||||
}
|
||||
|
||||
public function getName() {
|
||||
if(!is_null($this->getInput('type'))) {
|
||||
$typeFilter = array_search(
|
||||
$this->getInput('type'),
|
||||
self::PARAMETERS[$this->queriedContext]['type']['values']
|
||||
@@ -116,4 +129,7 @@ class AnimeUltimeBridge extends BridgeAbstract {
|
||||
return 'Latest ' . $typeFilter . ' - Anime-Ultime Bridge';
|
||||
}
|
||||
|
||||
return parent::getName();
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,27 +1,30 @@
|
||||
<?php
|
||||
class Arte7Bridge extends BridgeAbstract {
|
||||
|
||||
const MAINTAINER = "mitsukarenai";
|
||||
const NAME = "Arte +7";
|
||||
const URI = "http://www.arte.tv/";
|
||||
const MAINTAINER = 'mitsukarenai';
|
||||
const NAME = 'Arte +7';
|
||||
const URI = 'https://www.arte.tv/';
|
||||
const CACHE_TIMEOUT = 1800; // 30min
|
||||
const DESCRIPTION = "Returns newest videos from ARTE +7";
|
||||
const DESCRIPTION = 'Returns newest videos from ARTE +7';
|
||||
|
||||
const API_TOKEN = 'Nzc1Yjc1ZjJkYjk1NWFhN2I2MWEwMmRlMzAzNjI5NmU3NWU3ODg4ODJjOWMxNTMxYzEzZGRjYjg2ZGE4MmIwOA';
|
||||
|
||||
const PARAMETERS = array(
|
||||
'Catégorie (Français)' => array(
|
||||
'catfr' => array(
|
||||
'type' => 'list',
|
||||
'name' => 'Catégorie',
|
||||
'values' => array(
|
||||
'Toutes les vidéos (français)'=>'toutes-les-videos',
|
||||
'Actu & société'=>'actu-société',
|
||||
'Séries & fiction'=>'séries-fiction',
|
||||
'Cinéma'=>'cinéma',
|
||||
'Arts & spectacles classiques'=>'arts-spectacles-classiques',
|
||||
'Culture pop'=>'culture-pop',
|
||||
'Découverte'=>'découverte',
|
||||
'Histoire'=>'histoire',
|
||||
'Junior'=>'junior'
|
||||
|
||||
'Toutes les vidéos (français)' => null,
|
||||
'Actu & société' => 'ACT',
|
||||
'Séries & fiction' => 'SER',
|
||||
'Cinéma' => 'CIN',
|
||||
'Arts & spectacles classiques' => 'ARS',
|
||||
'Culture pop' => 'CPO',
|
||||
'Découverte' => 'DEC',
|
||||
'Histoire' => 'HIST',
|
||||
'Science' => 'SCI',
|
||||
'Autre' => 'AUT'
|
||||
)
|
||||
)
|
||||
),
|
||||
@@ -30,22 +33,22 @@
|
||||
'type' => 'list',
|
||||
'name' => 'Catégorie',
|
||||
'values' => array(
|
||||
'Alle Videos (deutsch)'=>'alle-videos',
|
||||
'Aktuelles & Gesellschaft'=>'aktuelles-gesellschaft',
|
||||
'Fernsehfilme & Serien'=>'fernsehfilme-serien',
|
||||
'Kino'=>'kino',
|
||||
'Kunst & Kultur'=>'kunst-kultur',
|
||||
'Popkultur & Alternativ'=>'popkultur-alternativ',
|
||||
'Entdeckung'=>'entdeckung',
|
||||
'Geschichte'=>'geschichte',
|
||||
'Junior'=>'junior'
|
||||
'Alle Videos (deutsch)' => null,
|
||||
'Aktuelles & Gesellschaft' => 'ACT',
|
||||
'Fernsehfilme & Serien' => 'SER',
|
||||
'Kino' => 'CIN',
|
||||
'Kunst & Kultur' => 'ARS',
|
||||
'Popkultur & Alternativ' => 'CPO',
|
||||
'Entdeckung' => 'DEC',
|
||||
'Geschichte' => 'HIST',
|
||||
'Wissenschaft' => 'SCI',
|
||||
'Sonstiges' => 'AUT'
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
public function collectData(){
|
||||
|
||||
switch($this->queriedContext) {
|
||||
case 'Catégorie (Français)':
|
||||
$category = $this->getInput('catfr');
|
||||
@@ -57,33 +60,39 @@
|
||||
break;
|
||||
}
|
||||
|
||||
$url = self::URI.'guide/'.$lang.'/plus7/'.$category;
|
||||
$input = getContents($url) or die('Could not request ARTE.');
|
||||
if(strpos($input, 'categoryVideoSet') !== FALSE){
|
||||
$input = explode('categoryVideoSet="', $input);
|
||||
$input = explode('}}', $input[1]);
|
||||
$input = $input[0].'}}';
|
||||
}else{
|
||||
$input = explode('videoSet="', $input);
|
||||
$input = explode('}]}', $input[1]);
|
||||
$input = $input[0].'}]}';
|
||||
}
|
||||
$url = 'https://api.arte.tv/api/opa/v3/videos?sort=-lastModified&limit=10&language='
|
||||
. $lang
|
||||
. ($category != null ? '&category.code=' . $category : '');
|
||||
|
||||
$input_json = json_decode(html_entity_decode($input, ENT_QUOTES), TRUE);
|
||||
$header = array(
|
||||
'Authorization: Bearer ' . self::API_TOKEN
|
||||
);
|
||||
|
||||
$input = getContents($url, $header) or die('Could not request ARTE.');
|
||||
$input_json = json_decode($input, true);
|
||||
|
||||
foreach($input_json['videos'] as $element) {
|
||||
|
||||
$item = array();
|
||||
$item['uri'] = str_replace("autoplay=1", "", $element['url']);
|
||||
$item['uri'] = $element['url'];
|
||||
$item['id'] = $element['id'];
|
||||
$hack_broadcast_time = $element['rights_end'];
|
||||
$hack_broadcast_time = strtok($hack_broadcast_time, 'T');
|
||||
$hack_broadcast_time = strtok('T');
|
||||
$item['timestamp'] = strtotime($element['scheduled_on'].'T'.$hack_broadcast_time);
|
||||
|
||||
$item['timestamp'] = strtotime($element['videoRightsBegin']);
|
||||
$item['title'] = $element['title'];
|
||||
|
||||
if(!empty($element['subtitle']))
|
||||
$item['title'] = $element['title'] . ' | ' . $element['subtitle'];
|
||||
$item['duration'] = round((int)$element['duration']/60);
|
||||
$item['content'] = $element['teaser'].'<br><br>'.$item['duration'].'min<br><a href="'.$item['uri'].'"><img src="' . $element['thumbnail_url'] . '" /></a>';
|
||||
|
||||
$item['duration'] = round((int)$element['durationSeconds'] / 60);
|
||||
$item['content'] = $element['teaserText']
|
||||
. '<br><br>'
|
||||
. $item['duration']
|
||||
. 'min<br><a href="'
|
||||
. $item['uri']
|
||||
. '"><img src="'
|
||||
. $element['mainImage']['url']
|
||||
. '" /></a>';
|
||||
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
|
@@ -1,11 +1,11 @@
|
||||
<?php
|
||||
class AskfmBridge extends BridgeAbstract {
|
||||
|
||||
const MAINTAINER = "az5he6ch";
|
||||
const NAME = "Ask.fm Answers";
|
||||
const URI = "http://ask.fm/";
|
||||
const MAINTAINER = 'az5he6ch';
|
||||
const NAME = 'Ask.fm Answers';
|
||||
const URI = 'https://ask.fm/';
|
||||
const CACHE_TIMEOUT = 300; //5 min
|
||||
const DESCRIPTION = "Returns answers from an Ask.fm user";
|
||||
const DESCRIPTION = 'Returns answers from an Ask.fm user';
|
||||
const PARAMETERS = array(
|
||||
'Ask.fm username' => array(
|
||||
'u' => array(
|
||||
@@ -23,17 +23,31 @@ class AskfmBridge extends BridgeAbstract{
|
||||
$item = array();
|
||||
$item['uri'] = self::URI . $element->find('a.streamItemsAge', 0)->href;
|
||||
$question = trim($element->find('h1.streamItemContent-question', 0)->innertext);
|
||||
$item['title'] = trim(htmlspecialchars_decode($element->find('h1.streamItemContent-question',0)->plaintext, ENT_QUOTES));
|
||||
|
||||
$item['title'] = trim(
|
||||
htmlspecialchars_decode($element->find('h1.streamItemContent-question', 0)->plaintext,
|
||||
ENT_QUOTES
|
||||
)
|
||||
);
|
||||
|
||||
$answer = trim($element->find('p.streamItemContent-answer', 0)->innertext);
|
||||
#$item['update'] = $element->find('a.streamitemsage',0)->data-hint; // Doesn't work, DOM parser doesn't seem to like data-hint, dunno why
|
||||
$visual = $element->find('div.streamItemContent-visual',0)->innertext; // This probably should be cleaned up, especially for YouTube embeds
|
||||
|
||||
// Doesn't work, DOM parser doesn't seem to like data-hint, dunno why
|
||||
#$item['update'] = $element->find('a.streamitemsage',0)->data-hint;
|
||||
|
||||
// This probably should be cleaned up, especially for YouTube embeds
|
||||
$visual = $element->find('div.streamItemContent-visual', 0)->innertext;
|
||||
//Fix tracking links, also doesn't work
|
||||
foreach($element->find('a') as $link) {
|
||||
if(strpos($link->href, 'l.ask.fm') !== false) {
|
||||
#$link->href = str_replace('#_=_', '', get_headers($link->href, 1)['Location']); // Too slow
|
||||
|
||||
// Too slow
|
||||
#$link->href = str_replace('#_=_', '', get_headers($link->href, 1)['Location']);
|
||||
|
||||
$link->href = $link->plaintext;
|
||||
}
|
||||
}
|
||||
|
||||
$content = '<p>' . $question . '</p><p>' . $answer . '</p><p>' . $visual . '</p>';
|
||||
// Fix relative links without breaking // scheme used by YouTube stuff
|
||||
$content = preg_replace('#href="\/(?!\/)#', 'href="' . self::URI, $content);
|
||||
@@ -43,10 +57,18 @@ class AskfmBridge extends BridgeAbstract{
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
if(!is_null($this->getInput('u'))) {
|
||||
return self::NAME . ' : ' . $this->getInput('u');
|
||||
}
|
||||
|
||||
return parent::getName();
|
||||
}
|
||||
|
||||
public function getURI(){
|
||||
if(!is_null($this->getInput('u'))) {
|
||||
return self::URI . urlencode($this->getInput('u')) . '/answers/more?page=0';
|
||||
}
|
||||
|
||||
return parent::getURI();
|
||||
}
|
||||
}
|
||||
|
@@ -1,11 +1,11 @@
|
||||
<?php
|
||||
class BandcampBridge extends BridgeAbstract {
|
||||
|
||||
const MAINTAINER = "sebsauvage";
|
||||
const NAME = "Bandcamp Tag";
|
||||
const URI = "http://bandcamp.com/";
|
||||
const MAINTAINER = 'sebsauvage';
|
||||
const NAME = 'Bandcamp Tag';
|
||||
const URI = 'https://bandcamp.com/';
|
||||
const CACHE_TIMEOUT = 600; // 10min
|
||||
const DESCRIPTION = "New bandcamp release by tag";
|
||||
const DESCRIPTION = 'New bandcamp release by tag';
|
||||
const PARAMETERS = array( array(
|
||||
'tag' => array(
|
||||
'name' => 'tag',
|
||||
@@ -24,9 +24,21 @@ class BandcampBridge extends BridgeAbstract{
|
||||
$uri = rtrim($uri, "')");
|
||||
|
||||
$item = array();
|
||||
$item['author'] = $release->find('div.itemsubtext',0)->plaintext . ' - ' . $release->find('div.itemtext',0)->plaintext;
|
||||
$item['title'] = $release->find('div.itemsubtext',0)->plaintext . ' - ' . $release->find('div.itemtext',0)->plaintext;
|
||||
$item['content'] = '<img src="' . $uri . '"/><br/>' . $release->find('div.itemsubtext',0)->plaintext . ' - ' . $release->find('div.itemtext',0)->plaintext;
|
||||
$item['author'] = $release->find('div.itemsubtext', 0)->plaintext
|
||||
. ' - '
|
||||
. $release->find('div.itemtext', 0)->plaintext;
|
||||
|
||||
$item['title'] = $release->find('div.itemsubtext', 0)->plaintext
|
||||
. ' - '
|
||||
. $release->find('div.itemtext', 0)->plaintext;
|
||||
|
||||
$item['content'] = '<img src="'
|
||||
. $uri
|
||||
. '"/><br/>'
|
||||
. $release->find('div.itemsubtext', 0)->plaintext
|
||||
. ' - '
|
||||
. $release->find('div.itemtext', 0)->plaintext;
|
||||
|
||||
$item['id'] = $release->find('a', 0)->getAttribute('href');
|
||||
$item['uri'] = $release->find('a', 0)->getAttribute('href');
|
||||
$this->items[] = $item;
|
||||
@@ -34,10 +46,18 @@ class BandcampBridge extends BridgeAbstract{
|
||||
}
|
||||
|
||||
public function getURI(){
|
||||
if(!is_null($this->getInput('tag'))) {
|
||||
return self::URI . 'tag/' . urlencode($this->getInput('tag')) . '?sort_field=date';
|
||||
}
|
||||
|
||||
return parent::getURI();
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return $this->getInput('tag') .' - '.'Bandcamp Tag';
|
||||
if(!is_null($this->getInput('tag'))) {
|
||||
return $this->getInput('tag') . ' - Bandcamp Tag';
|
||||
}
|
||||
|
||||
return parent::getName();
|
||||
}
|
||||
}
|
||||
|
@@ -1,19 +1,22 @@
|
||||
<?php
|
||||
class BastaBridge extends BridgeAbstract {
|
||||
const MAINTAINER = "qwertygc";
|
||||
const NAME = "Bastamag Bridge";
|
||||
const URI = "http://www.bastamag.net/";
|
||||
|
||||
const MAINTAINER = 'qwertygc';
|
||||
const NAME = 'Bastamag Bridge';
|
||||
const URI = 'http://www.bastamag.net/';
|
||||
const CACHE_TIMEOUT = 7200; // 2h
|
||||
const DESCRIPTION = "Returns the newest articles.";
|
||||
const DESCRIPTION = 'Returns the newest articles.';
|
||||
|
||||
public function collectData(){
|
||||
// Replaces all relative image URLs by absolute URLs. Relative URLs always start with 'local/'!
|
||||
function ReplaceImageUrl($content){
|
||||
// Replaces all relative image URLs by absolute URLs.
|
||||
// Relative URLs always start with 'local/'!
|
||||
function replaceImageUrl($content){
|
||||
return preg_replace('/src=["\']{1}([^"\']+)/ims', 'src=\'' . self::URI . '$1\'', $content);
|
||||
}
|
||||
|
||||
$html = getSimpleHTMLDOM(self::URI . 'spip.php?page=backend')
|
||||
or returnServerError('Could not request Bastamag.');
|
||||
|
||||
$limit = 0;
|
||||
|
||||
foreach($html->find('item') as $element) {
|
||||
@@ -22,11 +25,10 @@ class BastaBridge extends BridgeAbstract{
|
||||
$item['title'] = $element->find('title', 0)->innertext;
|
||||
$item['uri'] = $element->find('guid', 0)->plaintext;
|
||||
$item['timestamp'] = strtotime($element->find('dc:date', 0)->plaintext);
|
||||
$item['content'] = ReplaceImageUrl(getSimpleHTMLDOM($item['uri'])->find('div.texte', 0)->innertext);
|
||||
$item['content'] = replaceImageUrl(getSimpleHTMLDOM($item['uri'])->find('div.texte', 0)->innertext);
|
||||
$this->items[] = $item;
|
||||
$limit++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
@@ -1,12 +1,11 @@
|
||||
<?php
|
||||
class BlaguesDeMerdeBridge extends BridgeAbstract {
|
||||
|
||||
const MAINTAINER = "superbaillot.net";
|
||||
const NAME = "Blagues De Merde";
|
||||
const URI = "http://www.blaguesdemerde.fr/";
|
||||
const MAINTAINER = 'superbaillot.net';
|
||||
const NAME = 'Blagues De Merde';
|
||||
const URI = 'http://www.blaguesdemerde.fr/';
|
||||
const CACHE_TIMEOUT = 7200; // 2h
|
||||
const DESCRIPTION = "Blagues De Merde";
|
||||
|
||||
const DESCRIPTION = 'Blagues De Merde';
|
||||
|
||||
public function collectData(){
|
||||
$html = getSimpleHTMLDOM(self::URI)
|
||||
@@ -15,19 +14,18 @@ class BlaguesDeMerdeBridge extends BridgeAbstract{
|
||||
foreach($html->find('article.joke_contener') as $element) {
|
||||
$item = array();
|
||||
$temp = $element->find('a');
|
||||
if(isset($temp[2]))
|
||||
{
|
||||
|
||||
if(isset($temp[2])) {
|
||||
$item['content'] = trim($element->find('div.joke_text_contener', 0)->innertext);
|
||||
$uri = $temp[2]->href;
|
||||
$item['uri'] = $uri;
|
||||
$item['title'] = substr($uri, (strrpos($uri, "/") + 1));
|
||||
$date = $element->find("li.bdm_date",0)->innertext;
|
||||
$date = $element->find('li.bdm_date', 0)->innertext;
|
||||
$time = mktime(0, 0, 0, substr($date, 3, 2), substr($date, 0, 2), substr($date, 6, 4));
|
||||
$item['timestamp'] = $time;
|
||||
$item['author'] = $element->find("li.bdm_pseudo",0)->innertext;;
|
||||
$item['author'] = $element->find('li.bdm_pseudo', 0)->innertext;
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
65
bridges/BloombergBridge.php
Normal file
65
bridges/BloombergBridge.php
Normal file
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
class BloombergBridge extends BridgeAbstract
|
||||
{
|
||||
const NAME = 'Bloomberg';
|
||||
const URI = 'https://www.bloomberg.com/';
|
||||
const DESCRIPTION = 'Trending stories from Bloomberg';
|
||||
const MAINTAINER = 'mdemoss';
|
||||
|
||||
const PARAMETERS = array(
|
||||
'Trending Stories' => array(),
|
||||
'From Search' => array(
|
||||
'q' => array(
|
||||
'name' => 'Keyword',
|
||||
'required' => true
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
public function getName()
|
||||
{
|
||||
switch($this->queriedContext) {
|
||||
case 'Trending Stories':
|
||||
return self::NAME . ' Trending Stories';
|
||||
case 'From Search':
|
||||
if (!is_null($this->getInput('q'))) {
|
||||
return self::NAME . ' Search : ' . $this->getInput('q');
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return parent::getName();
|
||||
}
|
||||
|
||||
public function collectData()
|
||||
{
|
||||
switch($this->queriedContext) {
|
||||
case 'Trending Stories': // Get list of top new <article>s from the front page.
|
||||
$html = getSimpleHTMLDOMCached($this->getURI(), 300);
|
||||
$stories = $html->find('ul.top-news-v3__stories article.top-news-v3-story');
|
||||
break;
|
||||
case 'From Search': // Get list of <article> elements from search.
|
||||
$html = getSimpleHTMLDOMCached(
|
||||
$this->getURI() .
|
||||
'search?sort=time:desc&page=1&query=' .
|
||||
urlencode($this->getInput('q')), 300
|
||||
);
|
||||
$stories = $html->find('div.search-result-items article.search-result-story');
|
||||
break;
|
||||
}
|
||||
foreach ($stories as $element) {
|
||||
$item['uri'] = $element->find('h1 a', 0)->href;
|
||||
if (preg_match('#^https://#i', $item['uri']) !== 1) {
|
||||
$item['uri'] = $this->getURI() . $item['uri'];
|
||||
}
|
||||
$articleHtml = getSimpleHTMLDOMCached($item['uri']);
|
||||
if (!$articleHtml) {
|
||||
continue;
|
||||
}
|
||||
$item['title'] = $element->find('h1 a', 0)->plaintext;
|
||||
$item['timestamp'] = strtotime($articleHtml->find('meta[name=iso-8601-publish-date],meta[name=date]', 0)->content);
|
||||
$item['content'] = $articleHtml->find('meta[name=description]', 0)->content;
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
}
|
@@ -3,18 +3,19 @@ require_once('GelbooruBridge.php');
|
||||
|
||||
class BooruprojectBridge extends GelbooruBridge {
|
||||
|
||||
const MAINTAINER = "mitsukarenai";
|
||||
const NAME = "Booruproject";
|
||||
const URI = "http://booru.org/";
|
||||
const DESCRIPTION = "Returns images from given page of booruproject";
|
||||
|
||||
const MAINTAINER = 'mitsukarenai';
|
||||
const NAME = 'Booruproject';
|
||||
const URI = 'http://booru.org/';
|
||||
const DESCRIPTION = 'Returns images from given page of booruproject';
|
||||
const PARAMETERS = array(
|
||||
'global' => array(
|
||||
'p' => array(
|
||||
'name' => 'page',
|
||||
'type' => 'number'
|
||||
),
|
||||
't'=>array('name'=>'tags')
|
||||
't' => array(
|
||||
'name' => 'tags'
|
||||
)
|
||||
),
|
||||
'Booru subdomain (subdomain.booru.org)' => array(
|
||||
'i' => array(
|
||||
@@ -27,10 +28,18 @@ class BooruprojectBridge extends GelbooruBridge{
|
||||
const PIDBYPAGE = 20;
|
||||
|
||||
public function getURI(){
|
||||
if(!is_null($this->getInput('i'))) {
|
||||
return 'http://' . $this->getInput('i') . '.booru.org/';
|
||||
}
|
||||
|
||||
return parent::getURI();
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
if(!is_null($this->getInput('i'))) {
|
||||
return static::NAME . ' ' . $this->getInput('i');
|
||||
}
|
||||
|
||||
return parent::getName();
|
||||
}
|
||||
}
|
||||
|
@@ -1,10 +1,10 @@
|
||||
<?php
|
||||
class CADBridge extends FeedExpander {
|
||||
const MAINTAINER = "nyutag";
|
||||
const NAME = "CAD Bridge";
|
||||
const URI = "http://www.cad-comic.com/";
|
||||
const MAINTAINER = 'nyutag';
|
||||
const NAME = 'CAD Bridge';
|
||||
const URI = 'http://www.cad-comic.com/';
|
||||
const CACHE_TIMEOUT = 7200; //2h
|
||||
const DESCRIPTION = "Returns the newest articles.";
|
||||
const DESCRIPTION = 'Returns the newest articles.';
|
||||
|
||||
public function collectData(){
|
||||
$this->collectExpandableDatas('http://cdn2.cad-comic.com/rss.xml', 10);
|
||||
@@ -12,11 +12,11 @@ class CADBridge extends FeedExpander {
|
||||
|
||||
protected function parseItem($newsItem){
|
||||
$item = parent::parseItem($newsItem);
|
||||
$item['content'] = $this->CADExtractContent($item['uri']);
|
||||
$item['content'] = $this->extractCADContent($item['uri']);
|
||||
return $item;
|
||||
}
|
||||
|
||||
private function CADExtractContent($url) {
|
||||
private function extractCADContent($url) {
|
||||
$html3 = getSimpleHTMLDOMCached($url);
|
||||
|
||||
// The request might fail due to missing https support or wrong URL
|
||||
@@ -43,4 +43,3 @@ class CADBridge extends FeedExpander {
|
||||
return '<img src="' . $img . '"/>';
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
@@ -5,36 +5,43 @@ class CNETBridge extends BridgeAbstract {
|
||||
const NAME = 'CNET News';
|
||||
const URI = 'http://www.cnet.com/';
|
||||
const CACHE_TIMEOUT = 1800; // 30min
|
||||
const DESCRIPTION = 'Returns the newest articles. <br /> You may specify a topic found in some section URLs, else all topics are selected.';
|
||||
const DESCRIPTION = 'Returns the newest articles. <br /> You may specify a
|
||||
topic found in some section URLs, else all topics are selected.';
|
||||
|
||||
const PARAMETERS = array( array(
|
||||
'topic'=>array('name'=>'Topic name')
|
||||
'topic' => array(
|
||||
'name' => 'Topic name'
|
||||
)
|
||||
));
|
||||
|
||||
public function collectData(){
|
||||
|
||||
function ExtractFromDelimiters($string, $start, $end) {
|
||||
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;
|
||||
}
|
||||
|
||||
function StripWithDelimiters($string, $start, $end) {
|
||||
return false;
|
||||
}
|
||||
|
||||
function stripWithDelimiters($string, $start, $end){
|
||||
while(strpos($string, $start) !== false) {
|
||||
$section_to_remove = substr($string, strpos($string, $start));
|
||||
$section_to_remove = substr($section_to_remove, 0, strpos($section_to_remove, $end) + strlen($end));
|
||||
$string = str_replace($section_to_remove, '', $string);
|
||||
} return $string;
|
||||
}
|
||||
|
||||
function CleanArticle($article_html) {
|
||||
return $string;
|
||||
}
|
||||
|
||||
function cleanArticle($article_html){
|
||||
$article_html = '<p>' . substr($article_html, strpos($article_html, '<p>') + 3);
|
||||
$article_html = StripWithDelimiters($article_html, '<span class="credit">', '</span>');
|
||||
$article_html = StripWithDelimiters($article_html, '<script', '</script>');
|
||||
$article_html = StripWithDelimiters($article_html, '<div class="shortcode related-links', '</div>');
|
||||
$article_html = StripWithDelimiters($article_html, '<a class="clickToEnlarge">', '</a>');
|
||||
$article_html = stripWithDelimiters($article_html, '<span class="credit">', '</span>');
|
||||
$article_html = stripWithDelimiters($article_html, '<script', '</script>');
|
||||
$article_html = stripWithDelimiters($article_html, '<div class="shortcode related-links', '</div>');
|
||||
$article_html = stripWithDelimiters($article_html, '<a class="clickToEnlarge">', '</a>');
|
||||
return $article_html;
|
||||
}
|
||||
|
||||
@@ -44,17 +51,23 @@ class CNETBridge extends BridgeAbstract {
|
||||
|
||||
foreach($html->find('div.assetBody') as $element) {
|
||||
if($limit < 8) {
|
||||
|
||||
$article_title = trim($element->find('h2', 0)->plaintext);
|
||||
$article_uri = self::URI . ($element->find('a', 0)->href);
|
||||
$article_timestamp = strtotime($element->find('time.assetTime', 0)->plaintext);
|
||||
$article_author = trim($element->find('a[rel=author]', 0)->plaintext);
|
||||
|
||||
if(!empty($article_title) && !empty($article_uri) && strpos($article_uri, '/news/') !== false) {
|
||||
|
||||
$article_html = getSimpleHTMLDOM($article_uri) or returnServerError('Could not request CNET: '.$article_uri);
|
||||
|
||||
$article_content = trim(CleanArticle(ExtractFromDelimiters($article_html, '<div class="articleContent', '<footer>')));
|
||||
$article_html = getSimpleHTMLDOM($article_uri)
|
||||
or returnServerError('Could not request CNET: ' . $article_uri);
|
||||
$article_content = trim(
|
||||
cleanArticle(
|
||||
extractFromDelimiters(
|
||||
$article_html,
|
||||
'<div class="articleContent',
|
||||
'<footer>'
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
$item = array();
|
||||
$item['uri'] = $article_uri;
|
||||
@@ -70,7 +83,11 @@ class CNETBridge extends BridgeAbstract {
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
if(!is_null($this->getInput('topic'))) {
|
||||
$topic = $this->getInput('topic');
|
||||
return 'CNET News Bridge' . (empty($topic) ? '' : ' - ' . $topic);
|
||||
}
|
||||
|
||||
return parent::getName();
|
||||
}
|
||||
}
|
||||
|
@@ -1,10 +1,10 @@
|
||||
<?php
|
||||
class CastorusBridge extends BridgeAbstract {
|
||||
const MAINTAINER = "logmanoriginal";
|
||||
const NAME = "Castorus Bridge";
|
||||
const MAINTAINER = 'logmanoriginal';
|
||||
const NAME = 'Castorus Bridge';
|
||||
const URI = 'http://www.castorus.com';
|
||||
const CACHE_TIMEOUT = 600; // 10min
|
||||
const DESCRIPTION = "Returns the latest changes";
|
||||
const DESCRIPTION = 'Returns the latest changes';
|
||||
|
||||
const PARAMETERS = array(
|
||||
'Get latest changes' => array(),
|
||||
@@ -28,8 +28,8 @@ class CastorusBridge extends BridgeAbstract {
|
||||
)
|
||||
);
|
||||
|
||||
// Extracts the tile from an actitiy
|
||||
private function ExtractActivityTitle($activity){
|
||||
// Extracts the title from an actitiy
|
||||
private function extractActivityTitle($activity){
|
||||
$title = $activity->find('a', 0);
|
||||
|
||||
if(!$title)
|
||||
@@ -39,7 +39,7 @@ class CastorusBridge extends BridgeAbstract {
|
||||
}
|
||||
|
||||
// Extracts the url from an actitiy
|
||||
private function ExtractActivityUrl($activity){
|
||||
private function extractActivityUrl($activity){
|
||||
$url = $activity->find('a', 0);
|
||||
|
||||
if(!$url)
|
||||
@@ -49,7 +49,7 @@ class CastorusBridge extends BridgeAbstract {
|
||||
}
|
||||
|
||||
// Extracts the time from an activity
|
||||
private function ExtractActivityTime($activity){
|
||||
private function extractActivityTime($activity){
|
||||
// Unfortunately the time is part of the parent node,
|
||||
// so we have to clear all child nodes first
|
||||
$nodes = $activity->find('*');
|
||||
@@ -65,7 +65,7 @@ class CastorusBridge extends BridgeAbstract {
|
||||
}
|
||||
|
||||
// Extracts the price change
|
||||
private function ExtractActivityPrice($activity){
|
||||
private function extractActivityPrice($activity){
|
||||
$price = $activity->find('span', 1);
|
||||
|
||||
if(!$price)
|
||||
@@ -91,17 +91,24 @@ class CastorusBridge extends BridgeAbstract {
|
||||
foreach($activities as $activity) {
|
||||
$item = array();
|
||||
|
||||
$item['title'] = $this->ExtractActivityTitle($activity);
|
||||
$item['uri'] = $this->ExtractActivityUrl($activity);
|
||||
$item['timestamp'] = $this->ExtractActivityTime($activity);
|
||||
$item['content'] = '<a href="' . $item['uri'] . '">' . $item['title'] . '</a><br><p>'
|
||||
. $this->ExtractActivityPrice($activity) . '</p>';
|
||||
$item['title'] = $this->extractActivityTitle($activity);
|
||||
$item['uri'] = $this->extractActivityUrl($activity);
|
||||
$item['timestamp'] = $this->extractActivityTime($activity);
|
||||
$item['content'] = '<a href="'
|
||||
. $item['uri']
|
||||
. '">'
|
||||
. $item['title']
|
||||
. '</a><br><p>'
|
||||
. $this->extractActivityPrice($activity)
|
||||
. '</p>';
|
||||
|
||||
if(isset($zip_filter) && !(substr($item['title'], 0, strlen($zip_filter)) === $zip_filter)){
|
||||
if(isset($zip_filter)
|
||||
&& !(substr($item['title'], 0, strlen($zip_filter)) === $zip_filter)) {
|
||||
continue; // Skip this item
|
||||
}
|
||||
|
||||
if(isset($city_filter) && !(substr($item['title'], strpos($item['title'], ' ') + 1, strlen($city_filter)) === $city_filter)){
|
||||
if(isset($city_filter)
|
||||
&& !(substr($item['title'], strpos($item['title'], ' ') + 1, strlen($city_filter)) === $city_filter)) {
|
||||
continue; // Skip this item
|
||||
}
|
||||
|
||||
|
@@ -1,11 +1,11 @@
|
||||
<?php
|
||||
class CollegeDeFranceBridge extends BridgeAbstract {
|
||||
|
||||
const MAINTAINER = "pit-fgfjiudghdf";
|
||||
const NAME = "CollegeDeFrance";
|
||||
const URI = "http://www.college-de-france.fr/";
|
||||
const MAINTAINER = 'pit-fgfjiudghdf';
|
||||
const NAME = 'CollegeDeFrance';
|
||||
const URI = 'http://www.college-de-france.fr/';
|
||||
const CACHE_TIMEOUT = 10800; // 3h
|
||||
const DESCRIPTION = "Returns the latest audio and video from CollegeDeFrance";
|
||||
const DESCRIPTION = 'Returns the latest audio and video from CollegeDeFrance';
|
||||
|
||||
public function collectData(){
|
||||
$months = array(
|
||||
@@ -22,34 +22,44 @@ class CollegeDeFranceBridge extends BridgeAbstract{
|
||||
'11' => 'nov.',
|
||||
'12' => 'déc.'
|
||||
);
|
||||
|
||||
// The "API" used by the site returns a list of partial HTML in this form
|
||||
/* <li>
|
||||
* <a href="/site/thomas-romer/guestlecturer-2016-04-15-14h30.htm" data-target="after">
|
||||
* <span class="date"><span class="list-icon list-icon-video"></span><span class="list-icon list-icon-audio"></span>15 avr. 2016</span>
|
||||
* <span class="date"><span class="list-icon list-icon-video"></span>
|
||||
* <span class="list-icon list-icon-audio"></span>15 avr. 2016</span>
|
||||
* <span class="lecturer">Christopher Hays</span>
|
||||
* <span class='title'>Imagery of Divine Suckling in the Hebrew Bible and the Ancient Near East</span>
|
||||
* </a>
|
||||
* </li>
|
||||
*/
|
||||
$html = getSimpleHTMLDOM(self::URI.'components/search-audiovideo.jsp?fulltext=&siteid=1156951719600&lang=FR&type=all')
|
||||
$html = getSimpleHTMLDOM(self::URI
|
||||
. 'components/search-audiovideo.jsp?fulltext=&siteid=1156951719600&lang=FR&type=all')
|
||||
or returnServerError('Could not request CollegeDeFrance.');
|
||||
|
||||
foreach($html->find('a[data-target]') as $element) {
|
||||
$item = array();
|
||||
$item['title'] = $element->find('.title', 0)->plaintext;
|
||||
|
||||
// Most relative URLs contains an hour in addition to the date, so let's use it
|
||||
// <a href="/site/yann-lecun/course-2016-04-08-11h00.htm" data-target="after">
|
||||
//
|
||||
// Sometimes there's an __1, perhaps it signifies an update "/site/patrick-boucheron/seminar-2016-05-03-18h00__1.htm"
|
||||
// Sometimes there's an __1, perhaps it signifies an update
|
||||
// "/site/patrick-boucheron/seminar-2016-05-03-18h00__1.htm"
|
||||
//
|
||||
// But unfortunately some don't have any hours info
|
||||
// <a href="/site/institut-physique/The-Mysteries-of-Decoherence-Sebastien-Gleyzes-[Video-3-35].htm" data-target="after">
|
||||
// <a href="/site/institut-physique/
|
||||
// The-Mysteries-of-Decoherence-Sebastien-Gleyzes-[Video-3-35].htm" data-target="after">
|
||||
$timezone = new DateTimeZone('Europe/Paris');
|
||||
// strpos($element->href, '201') will break in 2020 but it'll probably break prior to then due to site changes anyway
|
||||
|
||||
// strpos($element->href, '201') will break in 2020 but it'll
|
||||
// probably break prior to then due to site changes anyway
|
||||
$d = DateTime::createFromFormat(
|
||||
'!Y-m-d-H\hi',
|
||||
substr($element->href, strpos($element->href, '201'), 16),
|
||||
$timezone
|
||||
);
|
||||
|
||||
if(!$d) {
|
||||
$d = DateTime::createFromFormat(
|
||||
'!d m Y',
|
||||
@@ -61,8 +71,12 @@ class CollegeDeFranceBridge extends BridgeAbstract{
|
||||
$timezone
|
||||
);
|
||||
}
|
||||
|
||||
$item['timestamp'] = $d->format('U');
|
||||
$item['content'] = $element->find('.lecturer', 0)->innertext . ' - ' . $element->find('.title', 0)->innertext;
|
||||
$item['content'] = $element->find('.lecturer', 0)->innertext
|
||||
. ' - '
|
||||
. $element->find('.title', 0)->innertext;
|
||||
|
||||
$item['uri'] = self::URI . $element->href;
|
||||
$this->items[] = $item;
|
||||
}
|
||||
|
@@ -1,10 +1,10 @@
|
||||
<?php
|
||||
class CommonDreamsBridge extends FeedExpander {
|
||||
|
||||
const MAINTAINER = "nyutag";
|
||||
const NAME = "CommonDreams Bridge";
|
||||
const URI = "http://www.commondreams.org/";
|
||||
const DESCRIPTION = "Returns the newest articles.";
|
||||
const MAINTAINER = 'nyutag';
|
||||
const NAME = 'CommonDreams Bridge';
|
||||
const URI = 'http://www.commondreams.org/';
|
||||
const DESCRIPTION = 'Returns the newest articles.';
|
||||
|
||||
public function collectData(){
|
||||
$this->collectExpandableDatas('http://www.commondreams.org/rss.xml', 10);
|
||||
@@ -12,11 +12,11 @@ class CommonDreamsBridge extends FeedExpander {
|
||||
|
||||
protected function parseItem($newsItem){
|
||||
$item = parent::parseItem($newsItem);
|
||||
$item['content'] = $this->CommonDreamsExtractContent($item['uri']);
|
||||
$item['content'] = $this->extractContent($item['uri']);
|
||||
return $item;
|
||||
}
|
||||
|
||||
private function CommonDreamsExtractContent($url) {
|
||||
private function extractContent($url){
|
||||
$html3 = getSimpleHTMLDOMCached($url);
|
||||
$text = $html3->find('div[class=field--type-text-with-summary]', 0)->innertext;
|
||||
$html3->clear();
|
||||
|
@@ -1,34 +1,30 @@
|
||||
<?php
|
||||
class CopieDoubleBridge extends BridgeAbstract {
|
||||
|
||||
const MAINTAINER = "superbaillot.net";
|
||||
const NAME = "CopieDouble";
|
||||
const URI = "http://www.copie-double.com/";
|
||||
const MAINTAINER = 'superbaillot.net';
|
||||
const NAME = 'CopieDouble';
|
||||
const URI = 'http://www.copie-double.com/';
|
||||
const CACHE_TIMEOUT = 14400; // 4h
|
||||
const DESCRIPTION = "CopieDouble";
|
||||
const DESCRIPTION = 'CopieDouble';
|
||||
|
||||
public function collectData(){
|
||||
$html = getSimpleHTMLDOM(self::URI)
|
||||
or returnServerError('Could not request CopieDouble.');
|
||||
|
||||
$table = $html->find('table table', 2);
|
||||
|
||||
foreach($table->find('tr') as $element)
|
||||
{
|
||||
foreach($table->find('tr') as $element) {
|
||||
$td = $element->find('td', 0);
|
||||
if($td->class == "couleur_1")
|
||||
{
|
||||
$item = array();
|
||||
|
||||
if($td->class === 'couleur_1') {
|
||||
$item = array();
|
||||
$title = $td->innertext;
|
||||
$pos = strpos($title, "<a");
|
||||
$pos = strpos($title, '<a');
|
||||
$title = substr($title, 0, $pos);
|
||||
$item['title'] = $title;
|
||||
}
|
||||
elseif(strpos($element->innertext, "/images/suivant.gif") === false)
|
||||
{
|
||||
$a=$element->find("a", 0);
|
||||
} elseif(strpos($element->innertext, '/images/suivant.gif') === false) {
|
||||
$a = $element->find('a', 0);
|
||||
$item['uri'] = self::URI . $a->href;
|
||||
|
||||
$content = str_replace('src="/', 'src="/' . self::URI, $element->find("td", 0)->innertext);
|
||||
$content = str_replace('href="/', 'href="' . self::URI, $content);
|
||||
$item['content'] = $content;
|
||||
|
@@ -1,42 +1,40 @@
|
||||
<?php
|
||||
class CourrierInternationalBridge extends BridgeAbstract {
|
||||
|
||||
const MAINTAINER = "teromene";
|
||||
const NAME = "Courrier International Bridge";
|
||||
const URI = "http://CourrierInternational.com/";
|
||||
const MAINTAINER = 'teromene';
|
||||
const NAME = 'Courrier International Bridge';
|
||||
const URI = 'http://CourrierInternational.com/';
|
||||
const CACHE_TIMEOUT = 300; // 5 min
|
||||
const DESCRIPTION = "Courrier International bridge";
|
||||
const DESCRIPTION = 'Courrier International bridge';
|
||||
|
||||
public function collectData(){
|
||||
|
||||
$html = getSimpleHTMLDOM(self::URI)
|
||||
or returnServerError('Error.');
|
||||
|
||||
$element = $html->find("article");
|
||||
|
||||
$article_count = 1;
|
||||
|
||||
foreach($element as $article) {
|
||||
|
||||
$item = array();
|
||||
|
||||
$item['uri'] = $article->parent->getAttribute("href");
|
||||
$item['uri'] = $article->parent->getAttribute('href');
|
||||
|
||||
if(strpos($item['uri'], "http") === FALSE) {
|
||||
if(strpos($item['uri'], 'http') === false) {
|
||||
$item['uri'] = self::URI . $item['uri'];
|
||||
}
|
||||
|
||||
$page = getSimpleHTMLDOMCached($item['uri']);
|
||||
|
||||
$content = $page->find('.article-text', 0);
|
||||
|
||||
if(!$content) {
|
||||
$content = $page->find('.depeche-text', 0);
|
||||
}
|
||||
|
||||
$item['content'] = sanitize($content);
|
||||
$item['title'] = strip_tags($article->find(".title",0));
|
||||
$item['title'] = strip_tags($article->find('.title', 0));
|
||||
|
||||
$dateTime = date_parse($page->find("time",0));
|
||||
$dateTime = date_parse($page->find('time', 0));
|
||||
|
||||
$item['timestamp'] = mktime(
|
||||
$dateTime['hour'],
|
||||
@@ -49,13 +47,9 @@ class CourrierInternationalBridge extends BridgeAbstract{
|
||||
|
||||
$this->items[] = $item;
|
||||
$article_count ++;
|
||||
if($article_count > 5) break;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
if($article_count > 5)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
@@ -1,11 +1,11 @@
|
||||
<?php
|
||||
class CpasbienBridge extends BridgeAbstract {
|
||||
|
||||
const MAINTAINER = "lagaisse";
|
||||
const NAME = "Cpasbien Bridge";
|
||||
const URI = "http://www.cpasbien.io";
|
||||
const MAINTAINER = 'lagaisse';
|
||||
const NAME = 'Cpasbien Bridge';
|
||||
const URI = 'http://www.cpasbien.cm';
|
||||
const CACHE_TIMEOUT = 86400; // 24h
|
||||
const DESCRIPTION = "Returns latest torrents from a request query";
|
||||
const DESCRIPTION = 'Returns latest torrents from a request query';
|
||||
|
||||
const PARAMETERS = array( array(
|
||||
'q' => array(
|
||||
@@ -21,15 +21,18 @@ class CpasbienBridge extends BridgeAbstract {
|
||||
or returnServerError('No results for this query.');
|
||||
|
||||
foreach($html->find('#gauche', 0)->find('div') as $episode) {
|
||||
if ($episode->getAttribute('class')=='ligne0' ||
|
||||
$episode->getAttribute('class')=='ligne1')
|
||||
{
|
||||
$htmlepisode=getSimpleHTMLDOMCached($episode->find('a', 0)->getAttribute('href'));
|
||||
if($episode->getAttribute('class') == 'ligne0'
|
||||
|| $episode->getAttribute('class') == 'ligne1') {
|
||||
|
||||
$urlepisode = $episode->find('a', 0)->getAttribute('href');
|
||||
$htmlepisode = getSimpleHTMLDOMCached($urlepisode, 86400 * 366 * 30);
|
||||
|
||||
$item = array();
|
||||
$item['author'] = $episode->find('a', 0)->text();
|
||||
$item['title'] = $episode->find('a', 0)->text();
|
||||
$item['pubdate'] = $this->getCachedDate($urlepisode);
|
||||
$textefiche = $htmlepisode->find('#textefiche', 0)->find('p', 1);
|
||||
|
||||
if(isset($textefiche)) {
|
||||
$item['content'] = $textefiche->text();
|
||||
} else {
|
||||
@@ -46,8 +49,26 @@ class CpasbienBridge extends BridgeAbstract {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function getName(){
|
||||
if(!is_null($this->getInput('q'))) {
|
||||
return $this->getInput('q') . ' : ' . self::NAME;
|
||||
}
|
||||
|
||||
return parent::getName();
|
||||
}
|
||||
|
||||
private function getCachedDate($url){
|
||||
debugMessage('getting pubdate from url ' . $url . '');
|
||||
|
||||
// Initialize cache
|
||||
$cache = Cache::create('FileCache');
|
||||
$cache->setPath(CACHE_DIR . '/pages');
|
||||
|
||||
$params = [$url];
|
||||
$cache->setParameters($params);
|
||||
|
||||
// Get cachefile timestamp
|
||||
$time = $cache->getTime();
|
||||
return ($time !== false ? $time : time());
|
||||
}
|
||||
}
|
||||
|
@@ -1,11 +1,11 @@
|
||||
<?php
|
||||
class CryptomeBridge extends BridgeAbstract {
|
||||
|
||||
const MAINTAINER = "BoboTiG";
|
||||
const NAME = "Cryptome";
|
||||
const URI = "https://cryptome.org/";
|
||||
const MAINTAINER = 'BoboTiG';
|
||||
const NAME = 'Cryptome';
|
||||
const URI = 'https://cryptome.org/';
|
||||
const CACHE_TIMEOUT = 21600; //6h
|
||||
const DESCRIPTION = "Returns the N most recent documents.";
|
||||
const DESCRIPTION = 'Returns the N most recent documents.';
|
||||
|
||||
const PARAMETERS = array( array(
|
||||
'n' => array(
|
||||
@@ -19,18 +19,24 @@ class CryptomeBridge extends BridgeAbstract{
|
||||
public function collectData(){
|
||||
$html = getSimpleHTMLDOM(self::URI)
|
||||
or returnServerError('Could not request Cryptome.');
|
||||
|
||||
$number = $this->getInput('n');
|
||||
if (!empty($number)) { /* number of documents */
|
||||
|
||||
/* number of documents */
|
||||
if(!empty($number)) {
|
||||
$num = min($number, 20);
|
||||
}
|
||||
|
||||
|
||||
foreach($html->find('pre') as $element) {
|
||||
for($i = 0; $i < $num; ++$i) {
|
||||
$item = array();
|
||||
$item['uri'] = self::URI . substr($element->find('a', $i)->href, 20);
|
||||
$item['title'] = substr($element->find('b', $i)->plaintext, 22);
|
||||
$item['content'] = preg_replace('#http://cryptome.org/#', self::URI, $element->find('b', $i)->innertext);
|
||||
$item['content'] = preg_replace(
|
||||
'#http://cryptome.org/#',
|
||||
self::URI,
|
||||
$element->find('b', $i)->innertext
|
||||
);
|
||||
$this->items[] = $item;
|
||||
}
|
||||
break;
|
||||
|
@@ -1,11 +1,11 @@
|
||||
<?php
|
||||
class DailymotionBridge extends BridgeAbstract {
|
||||
|
||||
const MAINTAINER = "mitsukarenai";
|
||||
const NAME = "Dailymotion Bridge";
|
||||
const URI = "https://www.dailymotion.com/";
|
||||
const MAINTAINER = 'mitsukarenai';
|
||||
const NAME = 'Dailymotion Bridge';
|
||||
const URI = 'https://www.dailymotion.com/';
|
||||
const CACHE_TIMEOUT = 10800; // 3h
|
||||
const DESCRIPTION = "Returns the 5 newest videos by username/playlist or search";
|
||||
const DESCRIPTION = 'Returns the 5 newest videos by username/playlist or search';
|
||||
|
||||
const PARAMETERS = array (
|
||||
'By username' => array(
|
||||
@@ -14,14 +14,12 @@ class DailymotionBridge extends BridgeAbstract{
|
||||
'required' => true
|
||||
)
|
||||
),
|
||||
|
||||
'By playlist id' => array(
|
||||
'p' => array(
|
||||
'name' => 'playlist id',
|
||||
'required' => true
|
||||
)
|
||||
),
|
||||
|
||||
'From search results' => array(
|
||||
's' => array(
|
||||
'name' => 'Search keyword',
|
||||
@@ -34,7 +32,7 @@ class DailymotionBridge extends BridgeAbstract{
|
||||
)
|
||||
);
|
||||
|
||||
function getMetadata($id) {
|
||||
protected function getMetadata($id){
|
||||
$metadata = array();
|
||||
$html2 = getSimpleHTMLDOM(self::URI . 'video/' . $id);
|
||||
if(!$html2) {
|
||||
@@ -42,7 +40,9 @@ class DailymotionBridge extends BridgeAbstract{
|
||||
}
|
||||
|
||||
$metadata['title'] = $html2->find('meta[property=og:title]', 0)->getAttribute('content');
|
||||
$metadata['timestamp'] = strtotime($html2->find('meta[property=video:release_date]', 0)->getAttribute('content') );
|
||||
$metadata['timestamp'] = strtotime(
|
||||
$html2->find('meta[property=video:release_date]', 0)->getAttribute('content')
|
||||
);
|
||||
$metadata['thumbnailUri'] = $html2->find('meta[property=og:image]', 0)->getAttribute('content');
|
||||
$metadata['uri'] = $html2->find('meta[property=og:url]', 0)->getAttribute('content');
|
||||
return $metadata;
|
||||
@@ -67,7 +67,17 @@ class DailymotionBridge extends BridgeAbstract{
|
||||
$item['uri'] = $metadata['uri'];
|
||||
$item['title'] = $metadata['title'];
|
||||
$item['timestamp'] = $metadata['timestamp'];
|
||||
$item['content'] = '<a href="' . $item['uri'] . '"><img src="' . $metadata['thumbnailUri'] . '" /></a><br><a href="' . $item['uri'] . '">' . $item['title'] . '</a>';
|
||||
|
||||
$item['content'] = '<a href="'
|
||||
. $item['uri']
|
||||
. '"><img src="'
|
||||
. $metadata['thumbnailUri']
|
||||
. '" /></a><br><a href="'
|
||||
. $item['uri']
|
||||
. '">'
|
||||
. $item['title']
|
||||
. '</a>';
|
||||
|
||||
$this->items[] = $item;
|
||||
$count++;
|
||||
}
|
||||
@@ -85,6 +95,7 @@ class DailymotionBridge extends BridgeAbstract{
|
||||
case 'From search results':
|
||||
$specific = $this->getInput('s');
|
||||
break;
|
||||
default: return parent::getName();
|
||||
}
|
||||
|
||||
return $specific . ' : Dailymotion Bridge';
|
||||
@@ -94,20 +105,18 @@ class DailymotionBridge extends BridgeAbstract{
|
||||
$uri = self::URI;
|
||||
switch($this->queriedContext) {
|
||||
case 'By username':
|
||||
$uri.='user/'
|
||||
.urlencode($this->getInput('u')).'/1';
|
||||
$uri .= 'user/' . urlencode($this->getInput('u')) . '/1';
|
||||
break;
|
||||
case 'By playlist id':
|
||||
$uri.='playlist/'
|
||||
.urlencode(strtok($this->getInput('p'), '_'));
|
||||
$uri .= 'playlist/' . urlencode(strtok($this->getInput('p'), '_'));
|
||||
break;
|
||||
case 'From search results':
|
||||
$uri.='search/'
|
||||
.urlencode($this->getInput('s'));
|
||||
$uri .= 'search/' . urlencode($this->getInput('s'));
|
||||
if($this->getInput('pa')) {
|
||||
$uri .= '/' . $this->getInput('pa');
|
||||
}
|
||||
break;
|
||||
default: return parent::getURI();
|
||||
}
|
||||
return $uri;
|
||||
}
|
||||
|
@@ -1,11 +1,11 @@
|
||||
<?php
|
||||
class DanbooruBridge extends BridgeAbstract {
|
||||
|
||||
const MAINTAINER = "mitsukarenai";
|
||||
const NAME = "Danbooru";
|
||||
const URI = "http://donmai.us/";
|
||||
const MAINTAINER = 'mitsukarenai';
|
||||
const NAME = 'Danbooru';
|
||||
const URI = 'http://donmai.us/';
|
||||
const CACHE_TIMEOUT = 1800; // 30min
|
||||
const DESCRIPTION = "Returns images from given page";
|
||||
const DESCRIPTION = 'Returns images from given page';
|
||||
|
||||
const PARAMETERS = array(
|
||||
'global' => array(
|
||||
@@ -14,29 +14,45 @@ class DanbooruBridge extends BridgeAbstract{
|
||||
'defaultValue' => 1,
|
||||
'type' => 'number'
|
||||
),
|
||||
't'=>array('name'=>'tags')
|
||||
't' => array(
|
||||
'name' => 'tags'
|
||||
)
|
||||
),
|
||||
0 => array()
|
||||
);
|
||||
|
||||
const PATHTODATA = 'article';
|
||||
const IDATTRIBUTE = 'data-id';
|
||||
const TAGATTRIBUTE = 'alt';
|
||||
|
||||
protected function getFullURI(){
|
||||
return $this->getURI().'posts?'
|
||||
.'&page='.$this->getInput('p')
|
||||
return $this->getURI()
|
||||
. 'posts?&page=' . $this->getInput('p')
|
||||
. '&tags=' . urlencode($this->getInput('t'));
|
||||
}
|
||||
|
||||
protected function getTags($element){
|
||||
return $element->find('img', 0)->getAttribute(static::TAGATTRIBUTE);
|
||||
}
|
||||
|
||||
protected function getItemFromElement($element){
|
||||
// Fix links
|
||||
defaultLinkTo($element, $this->getURI());
|
||||
|
||||
$item = array();
|
||||
$item['uri'] = $this->getURI().$element->find('a', 0)->href;
|
||||
$item['uri'] = $element->find('a', 0)->href;
|
||||
$item['postid'] = (int)preg_replace("/[^0-9]/", '', $element->getAttribute(static::IDATTRIBUTE));
|
||||
$item['timestamp'] = time();
|
||||
$thumbnailUri = $this->getURI().$element->find('img', 0)->src;
|
||||
$item['tags'] = $element->find('img', 0)->getAttribute('alt');
|
||||
$thumbnailUri = $element->find('img', 0)->src;
|
||||
$item['tags'] = $this->getTags($element);
|
||||
$item['title'] = $this->getName() . ' | ' . $item['postid'];
|
||||
$item['content'] = '<a href="' . $item['uri'] . '"><img src="' . $thumbnailUri . '" /></a><br>Tags: '.$item['tags'];
|
||||
$item['content'] = '<a href="'
|
||||
. $item['uri']
|
||||
. '"><img src="'
|
||||
. $thumbnailUri
|
||||
. '" /></a><br>Tags: '
|
||||
. $item['tags'];
|
||||
|
||||
return $item;
|
||||
}
|
||||
|
||||
|
@@ -1,11 +1,11 @@
|
||||
<?php
|
||||
class DansTonChatBridge extends BridgeAbstract {
|
||||
|
||||
const MAINTAINER = "Astalaseven";
|
||||
const NAME = "DansTonChat Bridge";
|
||||
const URI = "http://danstonchat.com/";
|
||||
const MAINTAINER = 'Astalaseven';
|
||||
const NAME = 'DansTonChat Bridge';
|
||||
const URI = 'https://danstonchat.com/';
|
||||
const CACHE_TIMEOUT = 21600; //6h
|
||||
const DESCRIPTION = "Returns latest quotes from DansTonChat.";
|
||||
const DESCRIPTION = 'Returns latest quotes from DansTonChat.';
|
||||
|
||||
public function collectData(){
|
||||
|
||||
|
@@ -1,11 +1,11 @@
|
||||
<?php
|
||||
class DauphineLibereBridge extends FeedExpander {
|
||||
|
||||
const MAINTAINER = "qwertygc";
|
||||
const NAME = "Dauphine Bridge";
|
||||
const URI = "http://www.ledauphine.com/";
|
||||
const MAINTAINER = 'qwertygc';
|
||||
const NAME = 'Dauphine Bridge';
|
||||
const URI = 'http://www.ledauphine.com/';
|
||||
const CACHE_TIMEOUT = 7200; // 2h
|
||||
const DESCRIPTION = "Returns the newest articles.";
|
||||
const DESCRIPTION = 'Returns the newest articles.';
|
||||
|
||||
const PARAMETERS = array( array(
|
||||
'u' => array(
|
||||
@@ -43,15 +43,14 @@ class DauphineLibereBridge extends FeedExpander {
|
||||
|
||||
protected function parseItem($newsItem){
|
||||
$item = parent::parseItem($newsItem);
|
||||
$item['content'] = $this->ExtractContent($item['uri']);
|
||||
$item['content'] = $this->extractContent($item['uri']);
|
||||
return $item;
|
||||
}
|
||||
|
||||
private function ExtractContent($url) {
|
||||
private function extractContent($url){
|
||||
$html2 = getSimpleHTMLDOMCached($url);
|
||||
$text = $html2->find('div.column', 0)->innertext;
|
||||
$text = preg_replace('@<script[^>]*?>.*?</script>@si', '', $text);
|
||||
return $text;
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
471
bridges/DealabsBridge.php
Normal file
471
bridges/DealabsBridge.php
Normal file
@@ -0,0 +1,471 @@
|
||||
<?php
|
||||
class DealabsBridge extends BridgeAbstract {
|
||||
const NAME = 'Dealabs search bridge';
|
||||
const URI = 'https://www.dealabs.com/';
|
||||
const DESCRIPTION = 'Return the Dealabs search result using keywords';
|
||||
const MAINTAINER = 'sysadminstory';
|
||||
const PARAMETERS = array(
|
||||
'Recherche par Mot(s) clé(s)' => array (
|
||||
'q' => array(
|
||||
'name' => 'Mot(s) clé(s)',
|
||||
'type' => 'text',
|
||||
'required' => true
|
||||
),
|
||||
'hide_expired' => array(
|
||||
'name' => 'Masquer les éléments expirés',
|
||||
'type' => 'checkbox',
|
||||
'required' => 'true'
|
||||
),
|
||||
'hide_local' => array(
|
||||
'name' => 'Masquer les deals locaux',
|
||||
'type' => 'checkbox',
|
||||
'title' => 'Masquer les deals en magasins physiques',
|
||||
'required' => 'true'
|
||||
),
|
||||
'priceFrom' => array(
|
||||
'name' => 'Prix minimum',
|
||||
'type' => 'text',
|
||||
'title' => 'Prix mnimum en euros',
|
||||
'required' => 'false',
|
||||
'defaultValue' => ''
|
||||
),
|
||||
'priceTo' => array(
|
||||
'name' => 'Prix maximum',
|
||||
'type' => 'text',
|
||||
'title' => 'Prix maximum en euros',
|
||||
'required' => 'false',
|
||||
'defaultValue' => ''
|
||||
),
|
||||
),
|
||||
|
||||
'Deals par groupe' => array(
|
||||
'groupe' => array(
|
||||
'name' => 'Groupe',
|
||||
'type' => 'list',
|
||||
'required' => 'true',
|
||||
'title' => 'Groupe dont il faut afficher les deals',
|
||||
'values' => array(
|
||||
'Accessoires & gadgets' => 'accessoires-gadgets',
|
||||
'Alimentation & boissons' => 'alimentation-boissons',
|
||||
'Animaux' => 'animaux',
|
||||
'Applis & logiciels' => 'applis-logiciels',
|
||||
'Consoles & jeux vidéo' => 'consoles-jeux-video',
|
||||
'Culture & divertissement' => 'culture-divertissement',
|
||||
'Gratuit' => 'gratuit',
|
||||
'Image, son & vidéo' => 'image-son-video',
|
||||
'Informatique' => 'informatique',
|
||||
'Jeux & jouets' => 'jeux-jouets',
|
||||
'Maison & jardin' => 'maison-jardin',
|
||||
'Mode & accessoires' => 'mode-accessoires',
|
||||
'Santé & cosmétiques' => 'hygiene-sante-cosmetiques',
|
||||
'Services divers' => 'services-divers',
|
||||
'Sports & plein air' => 'sports-plein-air',
|
||||
'Téléphonie' => 'telephonie',
|
||||
'Voyages & sorties' => 'voyages-sorties-restaurants'
|
||||
)
|
||||
),
|
||||
'ordre' => array(
|
||||
'name' => 'Trier par',
|
||||
'type' => 'list',
|
||||
'required' => 'true',
|
||||
'title' => 'Ordre de tri des deals',
|
||||
'values' => array(
|
||||
'Du deal le plus Hot au moins Hot' => '',
|
||||
'Du deal le plus récent au plus ancien' => '-nouveaux',
|
||||
'Du deal le plus commentés au moins commentés' => '-commentes'
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
const CACHE_TIMEOUT = 3600;
|
||||
|
||||
public function collectData(){
|
||||
switch($this->queriedContext) {
|
||||
case 'Recherche par Mot(s) clé(s)':
|
||||
return $this->collectDataMotsCles();
|
||||
break;
|
||||
case 'Deals par groupe':
|
||||
return $this->collectDataGroupe();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Deal data from the choosen groupe in the choose order
|
||||
*/
|
||||
public function collectDataGroupe()
|
||||
{
|
||||
|
||||
$groupe = $this->getInput('groupe');
|
||||
$ordre = $this->getInput('ordre');
|
||||
|
||||
$url = self::URI
|
||||
. '/groupe/' . $groupe . $ordre;
|
||||
$this->collectDeals($url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Deal data from the choosen keywords and parameters
|
||||
*/
|
||||
public function collectDataMotsCles()
|
||||
{
|
||||
$q = $this->getInput('q');
|
||||
$hide_expired = $this->getInput('hide_expired');
|
||||
$hide_local = $this->getInput('hide_local');
|
||||
$priceFrom = $this->getInput('priceFrom');
|
||||
$priceTo = $this->getInput('priceFrom');
|
||||
|
||||
/* Even if the original website uses POST with the search page, GET works too */
|
||||
$url = self::URI
|
||||
. '/search/advanced?q='
|
||||
. urlencode($q)
|
||||
. '&hide_expired='. $hide_expired
|
||||
. '&hide_local='. $hide_local
|
||||
. '&priceFrom='. $priceFrom
|
||||
. '&priceTo='. $priceTo
|
||||
/* Some default parameters
|
||||
* search_fields : Search in Titres & Descriptions & Codes
|
||||
* sort_by : Sort the search by new deals
|
||||
* time_frame : Search will not be on a limited timeframe
|
||||
*/
|
||||
. '&search_fields[]=1&search_fields[]=2&search_fields[]=3&sort_by=new&time_frame=0';
|
||||
$this->collectDeals($url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Deal data using the given URL
|
||||
*/
|
||||
public function collectDeals($url){
|
||||
$html = getSimpleHTMLDOM($url)
|
||||
or returnServerError('Could not request Dealabs.');
|
||||
$list = $html->find('article');
|
||||
|
||||
// Deal Image Link CSS Selector
|
||||
$selectorImageLink = implode(
|
||||
' ', /* Notice this is a space! */
|
||||
array(
|
||||
'cept-thread-image-link',
|
||||
'imgFrame',
|
||||
'imgFrame--noBorder',
|
||||
'box--all-i',
|
||||
'thread-listImgCell',
|
||||
)
|
||||
);
|
||||
|
||||
// Deal Link CSS Selector
|
||||
$selectorLink = implode(
|
||||
' ', /* Notice this is a space! */
|
||||
array(
|
||||
'cept-tt',
|
||||
'thread-link',
|
||||
'linkPlain',
|
||||
)
|
||||
);
|
||||
|
||||
// Deal Hotness CSS Selector
|
||||
$selectorHot = implode(
|
||||
' ', /* Notice this is a space! */
|
||||
array(
|
||||
'flex',
|
||||
'flex--align-c',
|
||||
'flex--justify-space-between',
|
||||
'space--b-2',
|
||||
)
|
||||
);
|
||||
|
||||
// Deal Description CSS Selector
|
||||
$selectorDescription = implode(
|
||||
' ', /* Notice this is a space! */
|
||||
array(
|
||||
'cept-description-container',
|
||||
'overflow--wrap-break',
|
||||
'size--all-s',
|
||||
'size--fromW3-m',
|
||||
)
|
||||
);
|
||||
|
||||
// Deal Date CSS Selector
|
||||
$selectorDate = implode(
|
||||
' ', /* Notice this is a space! */
|
||||
array(
|
||||
'size--all-s',
|
||||
'flex',
|
||||
'flex--wrap',
|
||||
'flex--justify-e',
|
||||
'flex--grow-1',
|
||||
)
|
||||
);
|
||||
|
||||
// If there is no results, we don't parse the content because it display some random deals
|
||||
$noresult = $html->find('h3[class=size--all-l size--fromW2-xl size--fromW3-xxl]', 0);
|
||||
if($noresult != null && $noresult->plaintext == 'Il n'y a rien à afficher pour le moment :(') {
|
||||
$this->items = array();
|
||||
} else {
|
||||
foreach($list as $deal) {
|
||||
$item = array();
|
||||
$item['uri'] = $deal->find('div[class=threadGrid-title]', 0)->find('a', 0)->href;
|
||||
$item['title'] = $deal->find('a[class*='. $selectorLink .']', 0
|
||||
)->plaintext;
|
||||
$item['author'] = $deal->find('span.thread-username', 0)->plaintext;
|
||||
$item['content'] = '<table><tr><td><a href="'
|
||||
. $deal->find(
|
||||
'a[class*='. $selectorImageLink .']', 0)->href
|
||||
. '"><img src="'
|
||||
. $this->getImage($deal)
|
||||
. '"/></td><td><h2><a href="'
|
||||
. $deal->find('a[class*='. $selectorLink .']', 0)->href
|
||||
. '">'
|
||||
. $deal->find('a[class*='. $selectorLink .']', 0)->innertext
|
||||
. '</a></h2>'
|
||||
. $this->getPrix($deal)
|
||||
. $this->getReduction($deal)
|
||||
. $this->getExpedition($deal)
|
||||
. $this->getLivraison($deal)
|
||||
. $this->getOrigine($deal)
|
||||
. $deal->find('div[class='. $selectorDescription .']', 0)->innertext
|
||||
. '</td><td>'
|
||||
. $deal->find('div[class='. $selectorHot .']', 0)->children(0)->outertext
|
||||
. '</td></table>';
|
||||
$dealDateDiv = $deal->find('div[class='. $selectorDate .']', 0)
|
||||
->find('span[class=hide--toW3]');
|
||||
$itemDate = end($dealDateDiv)->plaintext;
|
||||
if(substr( $itemDate, 0, 6 ) === 'il y a') {
|
||||
$item['timestamp'] = $this->relativeDateToTimestamp($itemDate);
|
||||
} else {
|
||||
$item['timestamp'] = $this->parseDate($itemDate);
|
||||
}
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Price from a Deal if it exists
|
||||
* @return string String of the deal price
|
||||
*/
|
||||
private function getPrix($deal)
|
||||
{
|
||||
if($deal->find(
|
||||
'span[class*=thread-price]', 0) != null) {
|
||||
return '<div>Prix : '
|
||||
. $deal->find(
|
||||
'span[class*=thread-price]', 0
|
||||
)->plaintext
|
||||
. '</div>';
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the Shipping costs from a Deal if it exists
|
||||
* @return string String of the deal shipping Cost
|
||||
*/
|
||||
private function getLivraison($deal)
|
||||
{
|
||||
if($deal->find('span[class*=cept-shipping-price]', 0) != null) {
|
||||
if($deal->find('span[class*=cept-shipping-price]', 0)->children(0) != null) {
|
||||
return '<div>Livraison : '
|
||||
. $deal->find('span[class*=cept-shipping-price]', 0)->children(0)->innertext
|
||||
. '</div>';
|
||||
} else {
|
||||
return '<div>Livraison : '
|
||||
. $deal->find('span[class*=cept-shipping-price]', 0)->innertext
|
||||
. '</div>';
|
||||
}
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the source of a Deal if it exists
|
||||
* @return string String of the deal source
|
||||
*/
|
||||
private function getOrigine($deal)
|
||||
{
|
||||
if($deal->find('a[class=text--color-greyShade]', 0) != null) {
|
||||
return '<div>Origine : '
|
||||
. $deal->find('a[class=text--color-greyShade]', 0)->outertext
|
||||
. '</div>';
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the original Price and discout from a Deal if it exists
|
||||
* @return string String of the deal original price and discount
|
||||
*/
|
||||
private function getReduction($deal)
|
||||
{
|
||||
if($deal->find('span[class*=mute--text text--lineThrough]', 0) != null) {
|
||||
return '<div>Réduction : <span style="text-decoration: line-through;">'
|
||||
. $deal->find(
|
||||
'span[class*=mute--text text--lineThrough]', 0
|
||||
)->plaintext
|
||||
. '</span> '
|
||||
. $deal->find('span[class=space--ml-1 size--all-l size--fromW3-xl]', 0)->plaintext
|
||||
. '</div>';
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Picture URL from a Deal if it exists
|
||||
* @return string String of the deal Picture URL
|
||||
*/
|
||||
private function getImage($deal)
|
||||
{
|
||||
|
||||
$selectorLazy = implode(
|
||||
' ', /* Notice this is a space! */
|
||||
array(
|
||||
'thread-image',
|
||||
'width--all-auto',
|
||||
'height--all-auto',
|
||||
'imgFrame-img',
|
||||
'cept-thread-img',
|
||||
'img--dummy',
|
||||
'js-lazy-img'
|
||||
)
|
||||
);
|
||||
|
||||
$selectorPlain = implode(
|
||||
' ', /* Notice this is a space! */
|
||||
array(
|
||||
'thread-image',
|
||||
'width--all-auto',
|
||||
'height--all-auto',
|
||||
'imgFrame-img',
|
||||
'cept-thread-img'
|
||||
)
|
||||
);
|
||||
if($deal->find('img[class='. $selectorLazy .']', 0) != null) {
|
||||
return json_decode(
|
||||
html_entity_decode(
|
||||
$deal->find('img[class='. $selectorLazy .']', 0)
|
||||
->getAttribute('data-lazy-img')))->{'src'};
|
||||
} else {
|
||||
return $deal->find('img[class='. $selectorPlain .']', 0 )->src;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the originating country from a Deal if it existsa
|
||||
* @return string String of the deal originating country
|
||||
*/
|
||||
private function getExpedition($deal)
|
||||
{
|
||||
$selector = implode(
|
||||
' ', /* Notice this is a space! */
|
||||
array(
|
||||
'meta-ribbon',
|
||||
'overflow--wrap-off',
|
||||
'space--l-3',
|
||||
'text--color-greyShade'
|
||||
)
|
||||
);
|
||||
if($deal->find('span[class='. $selector .']', 0) != null) {
|
||||
return '<div>'
|
||||
. $deal->find('span[class='. $selector .']', 0)->children(2)->plaintext
|
||||
. '</div>';
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms a French date into a timestam
|
||||
* @return int timestamp of the input date
|
||||
*/
|
||||
private function parseDate($string)
|
||||
{
|
||||
$month_fr = array(
|
||||
'janvier',
|
||||
'février',
|
||||
'mars',
|
||||
'avril',
|
||||
'mai',
|
||||
'juin',
|
||||
'juillet',
|
||||
'août',
|
||||
'septembre',
|
||||
'octobre',
|
||||
'novembre',
|
||||
'décembre'
|
||||
);
|
||||
$month_en = array(
|
||||
'January',
|
||||
'February',
|
||||
'March',
|
||||
'April',
|
||||
'May',
|
||||
'June',
|
||||
'July',
|
||||
'August',
|
||||
'September',
|
||||
'October',
|
||||
'November',
|
||||
'December'
|
||||
);
|
||||
$date_str = trim(str_replace($month_fr, $month_en, $string));
|
||||
|
||||
if(!preg_match('/[0-9]{4}/', $string)) {
|
||||
$date_str .= ' ' . date('Y');
|
||||
}
|
||||
$date_str .= ' 00:00';
|
||||
|
||||
$date = DateTime::createFromFormat('j F Y H:i', $date_str);
|
||||
return $date->getTimestamp();
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms a relate French date into a timestam
|
||||
* @return int timestamp of the input date
|
||||
*/
|
||||
private function relativeDateToTimestamp($str) {
|
||||
$date = new DateTime();
|
||||
$search = array(
|
||||
'il y a ',
|
||||
'min',
|
||||
'h',
|
||||
'jour',
|
||||
'jours',
|
||||
'mois',
|
||||
'ans',
|
||||
'et '
|
||||
);
|
||||
$replace = array(
|
||||
'-',
|
||||
'minute',
|
||||
'hour',
|
||||
'day',
|
||||
'month',
|
||||
'year',
|
||||
''
|
||||
);
|
||||
|
||||
$date->modify(str_replace($search, $replace, $str));
|
||||
return $date->getTimestamp();
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
switch($this->queriedContext) {
|
||||
case 'Recherche par Mot(s) clé(s)':
|
||||
return self::NAME . ' - Recherche : '. $this->getInput('q');
|
||||
break;
|
||||
case 'Deals par groupe':
|
||||
$values = self::PARAMETERS['Deals par groupe']['groupe']['values'];
|
||||
$groupe = array_search($this->getInput('groupe'), $values);
|
||||
return self::NAME . ' - Groupe : '. $groupe;
|
||||
break;
|
||||
default: // Return default value
|
||||
return self::NAME;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -1,10 +1,10 @@
|
||||
<?php
|
||||
class DemoBridge extends BridgeAbstract {
|
||||
|
||||
const MAINTAINER = "teromene";
|
||||
const NAME = "DemoBridge";
|
||||
const URI = "http://github.com/rss-bridge/rss-bridge";
|
||||
const DESCRIPTION = "Bridge used for demos";
|
||||
const MAINTAINER = 'teromene';
|
||||
const NAME = 'DemoBridge';
|
||||
const URI = 'http://github.com/rss-bridge/rss-bridge';
|
||||
const DESCRIPTION = 'Bridge used for demos';
|
||||
|
||||
const PARAMETERS = array(
|
||||
'testCheckbox' => array(
|
||||
@@ -13,7 +13,6 @@ class DemoBridge extends BridgeAbstract{
|
||||
'name' => 'test des checkbox'
|
||||
)
|
||||
),
|
||||
|
||||
'testList' => array(
|
||||
'testList' => array(
|
||||
'type' => 'list',
|
||||
@@ -24,7 +23,6 @@ class DemoBridge extends BridgeAbstract{
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
'testNumber' => array(
|
||||
'testNumber' => array(
|
||||
'type' => 'number',
|
||||
@@ -44,6 +42,5 @@ class DemoBridge extends BridgeAbstract{
|
||||
$item['uri'] = "http://example.com/test";
|
||||
|
||||
$this->items[] = $item;
|
||||
|
||||
}
|
||||
}
|
||||
|
146
bridges/DemonoidBridge.php
Normal file
146
bridges/DemonoidBridge.php
Normal file
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
class DemonoidBridge extends BridgeAbstract {
|
||||
|
||||
const MAINTAINER = 'metaMMA';
|
||||
const NAME = 'Demonoid';
|
||||
const URI = 'https://www.demonoid.pw/';
|
||||
const DESCRIPTION = 'Returns results for the keywords (in all categories or
|
||||
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(
|
||||
'q' => array(
|
||||
'name' => 'keywords/user ID/category, separated by semicolons',
|
||||
'exampleValue' => 'first list;second list;…',
|
||||
'required' => true
|
||||
),
|
||||
'crit' => array(
|
||||
'type' => 'list',
|
||||
'name' => 'Feed type',
|
||||
'values' => array(
|
||||
'search' => 'search',
|
||||
'category' => 'cat',
|
||||
'user' => 'usr'
|
||||
)
|
||||
),
|
||||
'catCheck' => array(
|
||||
'type' => 'checkbox',
|
||||
'name' => 'Specify category for keyword search ?',
|
||||
),
|
||||
'cat' => array(
|
||||
'name' => 'Category number',
|
||||
),
|
||||
));
|
||||
|
||||
public function collectData() {
|
||||
|
||||
$catBool = $this->getInput('catCheck');
|
||||
if($catBool) {
|
||||
$catNum = $this->getInput('cat');
|
||||
}
|
||||
$critList = $this->getInput('crit');
|
||||
|
||||
$keywordsList = explode(';', $this->getInput('q'));
|
||||
foreach($keywordsList as $keywords) {
|
||||
switch($critList) {
|
||||
case 'search':
|
||||
if($catBool == false) {
|
||||
$html = file_get_contents(
|
||||
self::URI .
|
||||
'files/?category=0&subcategory=All&quality=All&seeded=2&external=2&query=' .
|
||||
urlencode($keywords) . #not rawurlencode so space -> '+'
|
||||
'&uid=0&sort='
|
||||
) or returnServerError('Could not request Demonoid.');
|
||||
} else {
|
||||
$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;
|
||||
}
|
||||
|
||||
if(preg_match('~No torrents found~', $html)) {
|
||||
returnServerError('No result for query ' . $keywords);
|
||||
}
|
||||
|
||||
$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])) {
|
||||
date_default_timezone_set('UTC');
|
||||
$timestamp = mktime(0, 0, 0, gmdate('n'), gmdate('j'), gmdate('Y'));
|
||||
} else {
|
||||
preg_match('~(?<=ed on ).*\d+~', $dateStr[0], $fullDateStr);
|
||||
date_default_timezone_set('UTC');
|
||||
$dateObj = strptime($fullDateStr[0], '%A, %b %d, %Y');
|
||||
$timestamp = mktime(0, 0, 0, $dateObj['tm_mon'] + 1, $dateObj['tm_mday'], 1900 + $dateObj['tm_year']);
|
||||
}
|
||||
|
||||
$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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,11 +1,11 @@
|
||||
<?php
|
||||
class DeveloppezDotComBridge extends FeedExpander {
|
||||
|
||||
const MAINTAINER = "polopollo";
|
||||
const NAME = "Developpez.com Actus (FR)";
|
||||
const URI = "http://www.developpez.com/";
|
||||
const MAINTAINER = 'polopollo';
|
||||
const NAME = 'Developpez.com Actus (FR)';
|
||||
const URI = 'https://www.developpez.com/';
|
||||
const CACHE_TIMEOUT = 1800; // 30min
|
||||
const DESCRIPTION = "Returns the 15 newest posts from DeveloppezDotCom (full text).";
|
||||
const DESCRIPTION = 'Returns the 15 newest posts from DeveloppezDotCom (full text).';
|
||||
|
||||
public function collectData(){
|
||||
$this->collectExpandableDatas(self::URI . 'index/rss', 15);
|
||||
@@ -13,19 +13,13 @@ class DeveloppezDotComBridge extends FeedExpander {
|
||||
|
||||
protected function parseItem($newsItem){
|
||||
$item = parent::parseItem($newsItem);
|
||||
$item['content'] = $this->DeveloppezDotComExtractContent($item['uri']);
|
||||
$item['content'] = $this->extractContent($item['uri']);
|
||||
return $item;
|
||||
}
|
||||
|
||||
private function DeveloppezDotComStripCDATA($string) {
|
||||
$string = str_replace('<![CDATA[', '', $string);
|
||||
$string = str_replace(']]>', '', $string);
|
||||
return $string;
|
||||
}
|
||||
|
||||
// F***ing quotes from Microsoft Word badly encoded, here was the trick:
|
||||
// http://stackoverflow.com/questions/1262038/how-to-replace-microsoft-encoded-quotes-in-php
|
||||
private function convert_smart_quotes($string)
|
||||
private function convertSmartQuotes($string)
|
||||
{
|
||||
$search = array(chr(145),
|
||||
chr(146),
|
||||
@@ -33,18 +27,20 @@ class DeveloppezDotComBridge extends FeedExpander {
|
||||
chr(148),
|
||||
chr(151));
|
||||
|
||||
$replace = array("'",
|
||||
$replace = array(
|
||||
"'",
|
||||
"'",
|
||||
'"',
|
||||
'"',
|
||||
'-');
|
||||
'-'
|
||||
);
|
||||
|
||||
return str_replace($search, $replace, $string);
|
||||
}
|
||||
|
||||
private function DeveloppezDotComExtractContent($url) {
|
||||
private function extractContent($url){
|
||||
$articleHTMLContent = getSimpleHTMLDOMCached($url);
|
||||
$text = $this->convert_smart_quotes($articleHTMLContent->find('div.content', 0)->innertext);
|
||||
$text = $this->convertSmartQuotes($articleHTMLContent->find('div.content', 0)->innertext);
|
||||
$text = utf8_encode($text);
|
||||
return trim($text);
|
||||
}
|
||||
|
120
bridges/DiceBridge.php
Normal file
120
bridges/DiceBridge.php
Normal file
@@ -0,0 +1,120 @@
|
||||
<?php
|
||||
class DiceBridge extends BridgeAbstract {
|
||||
|
||||
const MAINTAINER = 'rogerdc';
|
||||
const NAME = 'Dice Unofficial RSS';
|
||||
const URI = 'https://www.dice.com/';
|
||||
const DESCRIPTION = 'The Unofficial Dice RSS';
|
||||
// const CACHE_TIMEOUT = 86400; // 1 day
|
||||
|
||||
const PARAMETERS = array(array(
|
||||
'for_one' => array(
|
||||
'name' => 'With at least one of the words',
|
||||
'required' => false,
|
||||
),
|
||||
'for_all' => array(
|
||||
'name' => 'With all of the words',
|
||||
'required' => false,
|
||||
),
|
||||
'for_exact' => array(
|
||||
'name' => 'With the exact phrase',
|
||||
'required' => false,
|
||||
),
|
||||
'for_none' => array(
|
||||
'name' => 'With none of these words',
|
||||
'required' => false,
|
||||
),
|
||||
'for_jt' => array(
|
||||
'name' => 'Within job title',
|
||||
'required' => false,
|
||||
),
|
||||
'for_com' => array(
|
||||
'name' => 'Within company name',
|
||||
'required' => false,
|
||||
),
|
||||
'for_loc' => array(
|
||||
'name' => 'City, State, or ZIP code',
|
||||
'required' => false,
|
||||
),
|
||||
'radius' => array(
|
||||
'name' => 'Radius in miles',
|
||||
'type' => 'list',
|
||||
'required' => false,
|
||||
'values' => array(
|
||||
'Exact Location' => 'El',
|
||||
'Within 5 miles' => '5',
|
||||
'Within 10 miles' => '10',
|
||||
'Within 20 miles' => '20',
|
||||
'Within 30 miles' => '0',
|
||||
'Within 40 miles' => '40',
|
||||
'Within 50 miles' => '50',
|
||||
'Within 75 miles' => '75',
|
||||
'Within 100 miles' => '100',
|
||||
),
|
||||
'defaultValue' => '0',
|
||||
),
|
||||
'jtype' => array(
|
||||
'name' => 'Job type',
|
||||
'type' => 'list',
|
||||
'required' => false,
|
||||
'values' => array(
|
||||
'Full-Time' => 'Full Time',
|
||||
'Part-Time' => 'Part Time',
|
||||
'Contract - Independent' => 'Contract Independent',
|
||||
'Contract - W2' => 'Contract W2',
|
||||
'Contract to Hire - Independent' => 'C2H Independent',
|
||||
'Contract to Hire - W2' => 'C2H W2',
|
||||
'Third Party - Contract - Corp-to-Corp' => 'Contract Corp-To-Corp',
|
||||
'Third Party - Contract to Hire - Corp-to-Corp' => 'C2H Corp-To-Corp',
|
||||
),
|
||||
'defaultValue' => 'Full Time',
|
||||
),
|
||||
'telecommute' => array(
|
||||
'name' => 'Telecommute',
|
||||
'type' => 'checkbox',
|
||||
),
|
||||
));
|
||||
|
||||
public function collectData() {
|
||||
$uri = 'https://www.dice.com/jobs/advancedResult.html';
|
||||
$uri .= '?for_one=' . urlencode($this->getInput('for_one'));
|
||||
$uri .= '&for_all=' . urlencode($this->getInput('for_all'));
|
||||
$uri .= '&for_exact=' . urlencode($this->getInput('for_exact'));
|
||||
$uri .= '&for_none=' . urlencode($this->getInput('for_none'));
|
||||
$uri .= '&for_jt=' . urlencode($this->getInput('for_jt'));
|
||||
$uri .= '&for_com=' . urlencode($this->getInput('for_com'));
|
||||
$uri .= '&for_loc=' . urlencode($this->getInput('for_loc'));
|
||||
if ($this->getInput('jtype')) {
|
||||
$uri .= '&jtype=' . urlencode($this->getInput('jtype'));
|
||||
}
|
||||
$uri .= '&sort=date&limit=100';
|
||||
$uri .= '&radius=' . urlencode($this->getInput('radius'));
|
||||
if ($this->getInput('telecommute')) {
|
||||
$uri .= '&telecommute=true';
|
||||
}
|
||||
|
||||
$html = getSimpleHTMLDOM($uri)
|
||||
or returnServerError('Could not request Dice.');
|
||||
foreach($html->find('div.complete-serp-result-div') as $element) {
|
||||
$item = array();
|
||||
// Title
|
||||
$masterLink = $element->find('a[id^=position]', 0);
|
||||
$item['title'] = $masterLink->title;
|
||||
// URL
|
||||
$uri = $masterLink->href;
|
||||
// $uri = substr($uri, 0, strrpos($uri, '?'));
|
||||
$item['uri'] = substr($uri, 0, strrpos($uri, '?'));
|
||||
// ID
|
||||
$item['id'] = $masterLink->value;
|
||||
// Image
|
||||
$image = $element->find('img', 0);
|
||||
if ($image)
|
||||
$item['image'] = $image->getAttribute('src');
|
||||
// Content
|
||||
$shortdesc = $element->find('.shortdesc', '0');
|
||||
$shortdesc = ($shortdesc) ? $shortdesc->innertext : '';
|
||||
$item['content'] = $shortdesc;
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
}
|
@@ -9,7 +9,8 @@ class DilbertBridge extends BridgeAbstract {
|
||||
|
||||
public function collectData(){
|
||||
|
||||
$html = getSimpleHTMLDOM($this->getURI()) or returnServerError('Could not request Dilbert: '.$this->getURI());
|
||||
$html = getSimpleHTMLDOM($this->getURI())
|
||||
or returnServerError('Could not request Dilbert: ' . $this->getURI());
|
||||
|
||||
foreach($html->find('section.comic-item') as $element) {
|
||||
|
||||
@@ -33,4 +34,3 @@ class DilbertBridge extends BridgeAbstract {
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
@@ -2,10 +2,8 @@
|
||||
require_once('Shimmie2Bridge.php');
|
||||
|
||||
class DollbooruBridge extends Shimmie2Bridge {
|
||||
|
||||
const MAINTAINER = "mitsukarenai";
|
||||
const NAME = "Dollbooru";
|
||||
const URI = "http://dollbooru.org/";
|
||||
const DESCRIPTION = "Returns images from given page";
|
||||
|
||||
const MAINTAINER = 'mitsukarenai';
|
||||
const NAME = 'Dollbooru';
|
||||
const URI = 'http://dollbooru.org/';
|
||||
const DESCRIPTION = 'Returns images from given page';
|
||||
}
|
||||
|
91
bridges/DribbbleBridge.php
Normal file
91
bridges/DribbbleBridge.php
Normal file
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
class DribbbleBridge extends BridgeAbstract {
|
||||
|
||||
const MAINTAINER = 'quentinus95';
|
||||
const NAME = 'Dribbble popular shots';
|
||||
const URI = 'https://dribbble.com';
|
||||
const CACHE_TIMEOUT = 1800;
|
||||
const DESCRIPTION = 'Returns the newest popular shots from Dribbble.';
|
||||
|
||||
public function collectData(){
|
||||
$html = getSimpleHTMLDOM(self::URI . '/shots')
|
||||
or returnServerError('Error while downloading the website content');
|
||||
|
||||
$json = $this->loadEmbeddedJsonData($html);
|
||||
|
||||
foreach($html->find('li[id^="screenshot-"]') as $shot) {
|
||||
$item = [];
|
||||
|
||||
$additional_data = $this->findJsonForShot($shot, $json);
|
||||
if ($additional_data === null) {
|
||||
$item['uri'] = self::URI . $shot->find('a', 0)->href;
|
||||
$item['title'] = $shot->find('.dribbble-over strong', 0)->plaintext;
|
||||
} else {
|
||||
$item['timestamp'] = strtotime($additional_data['published_at']);
|
||||
$item['uri'] = self::URI . $additional_data['path'];
|
||||
$item['title'] = $additional_data['title'];
|
||||
}
|
||||
|
||||
$item['author'] = trim($shot->find('.attribution-user a', 0)->plaintext);
|
||||
|
||||
$description = $shot->find('.comment', 0);
|
||||
$item['content'] = $description === null ? '' : $description->plaintext;
|
||||
|
||||
$preview_path = $shot->find('picture source', 0)->attr['srcset'];
|
||||
$item['content'] .= $this->getImageTag($preview_path, $item['title']);
|
||||
$item['enclosures'] = [$this->getFullSizeImagePath($preview_path)];
|
||||
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
private function loadEmbeddedJsonData($html){
|
||||
$json = [];
|
||||
$scripts = $html->find('script');
|
||||
|
||||
foreach($scripts as $script) {
|
||||
if(strpos($script->innertext, 'newestShots') !== false) {
|
||||
// fix single quotes
|
||||
$script->innertext = str_replace('\'', '"', $script->innertext);
|
||||
|
||||
// fix JavaScript JSON (why do they not adhere to the standard?)
|
||||
$script->innertext = preg_replace('/(\w+):/i', '"\1":', $script->innertext);
|
||||
|
||||
// find beginning of JSON array
|
||||
$start = strpos($script->innertext, '[');
|
||||
|
||||
// find end of JSON array, compensate for missing character!
|
||||
$end = strpos($script->innertext, '];') + 1;
|
||||
|
||||
// convert JSON to PHP array
|
||||
$json = json_decode(substr($script->innertext, $start, $end - $start), true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $json;
|
||||
}
|
||||
|
||||
private function findJsonForShot($shot, $json){
|
||||
foreach($json as $element) {
|
||||
if(strpos($shot->getAttribute('id'), (string)$element['id']) !== false) {
|
||||
return $element;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function getImageTag($preview_path, $title){
|
||||
return sprintf(
|
||||
'<br /> <a href="%s"><img src="%s" alt="%s" /></a>',
|
||||
$this->getFullSizeImagePath($preview_path),
|
||||
$preview_path,
|
||||
$title
|
||||
);
|
||||
}
|
||||
|
||||
private function getFullSizeImagePath($preview_path){
|
||||
return str_replace('_1x', '', $preview_path);
|
||||
}
|
||||
}
|
@@ -1,11 +1,11 @@
|
||||
<?php
|
||||
class DuckDuckGoBridge extends BridgeAbstract {
|
||||
|
||||
const MAINTAINER = "Astalaseven";
|
||||
const NAME = "DuckDuckGo";
|
||||
const URI = "https://duckduckgo.com/";
|
||||
const MAINTAINER = 'Astalaseven';
|
||||
const NAME = 'DuckDuckGo';
|
||||
const URI = 'https://duckduckgo.com/';
|
||||
const CACHE_TIMEOUT = 21600; // 6h
|
||||
const DESCRIPTION = "Returns results from DuckDuckGo.";
|
||||
const DESCRIPTION = 'Returns results from DuckDuckGo.';
|
||||
|
||||
const SORT_DATE = '+sort:date';
|
||||
const SORT_RELEVANCE = '';
|
||||
@@ -13,7 +13,8 @@ class DuckDuckGoBridge extends BridgeAbstract{
|
||||
const PARAMETERS = array( array(
|
||||
'u' => array(
|
||||
'name' => 'keyword',
|
||||
'required'=>true),
|
||||
'required' => true
|
||||
),
|
||||
'sort' => array(
|
||||
'name' => 'sort by',
|
||||
'type' => 'list',
|
||||
@@ -27,7 +28,7 @@ class DuckDuckGoBridge extends BridgeAbstract{
|
||||
));
|
||||
|
||||
public function collectData(){
|
||||
$html = getSimpleHTMLDOM(self::URI.'html/?q='.$this->getInput('u').$this->getInput('sort'))
|
||||
$html = getSimpleHTMLDOM(self::URI . 'html/?kd=-1&q=' . $this->getInput('u') . $this->getInput('sort'))
|
||||
or returnServerError('Could not request DuckDuckGo.');
|
||||
|
||||
foreach($html->find('div.results_links') as $element) {
|
||||
|
@@ -2,9 +2,10 @@
|
||||
class EZTVBridge extends BridgeAbstract {
|
||||
|
||||
const MAINTAINER = "alexAubin";
|
||||
const NAME = "EZTV";
|
||||
const URI = "https://eztv.ch/";
|
||||
const DESCRIPTION = "Returns list of *recent* torrents for a specific show on EZTV. Get showID from URLs in https://eztv.ch/shows/showID/show-full-name.";
|
||||
const NAME = 'EZTV';
|
||||
const URI = 'https://eztv.ch/';
|
||||
const DESCRIPTION = 'Returns list of *recent* torrents for a specific show
|
||||
on EZTV. Get showID from URLs in https://eztv.ch/shows/showID/show-full-name.';
|
||||
|
||||
const PARAMETERS = array( array(
|
||||
'i' => array(
|
||||
|
@@ -1,16 +1,16 @@
|
||||
<?php
|
||||
class EliteDangerousGalnetBridge extends BridgeAbstract
|
||||
{
|
||||
const MAINTAINER = "corenting";
|
||||
const NAME = "Elite: Dangerous Galnet";
|
||||
const URI = "https://community.elitedangerous.com/galnet/";
|
||||
const CACHE_TIMEOUT = 7200; // 2h
|
||||
const DESCRIPTION = "Returns the latest page of news from Galnet";
|
||||
class EliteDangerousGalnetBridge extends BridgeAbstract {
|
||||
|
||||
public function collectData()
|
||||
{
|
||||
const MAINTAINER = 'corenting';
|
||||
const NAME = 'Elite: Dangerous Galnet';
|
||||
const URI = 'https://community.elitedangerous.com/galnet/';
|
||||
const CACHE_TIMEOUT = 7200; // 2h
|
||||
const DESCRIPTION = 'Returns the latest page of news from Galnet';
|
||||
|
||||
public function collectData(){
|
||||
$html = getSimpleHTMLDOM(self::URI)
|
||||
or returnServerError('Error while downloading the website content');
|
||||
|
||||
foreach($html->find('div.article') as $element) {
|
||||
$item = array();
|
||||
|
||||
|
@@ -1,5 +1,6 @@
|
||||
<?php
|
||||
class ElsevierBridge extends BridgeAbstract {
|
||||
|
||||
const MAINTAINER = 'Pierre Mazière';
|
||||
const NAME = 'Elsevier journals recent articles';
|
||||
const URI = 'http://www.journals.elsevier.com/';
|
||||
@@ -16,7 +17,7 @@ class ElsevierBridge extends BridgeAbstract{
|
||||
));
|
||||
|
||||
// Extracts the list of names from an article as string
|
||||
private function ExtractArticleName ($article){
|
||||
private function extractArticleName($article){
|
||||
$names = $article->find('small', 0);
|
||||
if($names)
|
||||
return trim($names->plaintext);
|
||||
@@ -24,7 +25,7 @@ class ElsevierBridge extends BridgeAbstract{
|
||||
}
|
||||
|
||||
// Extracts the timestamp from an article
|
||||
private function ExtractArticleTimestamp ($article){
|
||||
private function extractArticleTimestamp($article){
|
||||
$time = $article->find('.article-info', 0);
|
||||
if($time) {
|
||||
$timestring = trim($time->plaintext);
|
||||
@@ -48,7 +49,7 @@ class ElsevierBridge extends BridgeAbstract{
|
||||
}
|
||||
|
||||
// Extracts the content from an article
|
||||
private function ExtractArticleContent ($article){
|
||||
private function extractArticleContent($article){
|
||||
$content = $article->find('.article-content', 0);
|
||||
if($content) {
|
||||
return trim($content->plaintext);
|
||||
@@ -58,17 +59,17 @@ class ElsevierBridge extends BridgeAbstract{
|
||||
|
||||
public function collectData(){
|
||||
$uri = self::URI . $this->getInput('j') . '/recent-articles/';
|
||||
$html = getSimpleHTMLDOM($uri) or returnServerError('No results for Elsevier journal '.$this->getInput('j'));
|
||||
$html = getSimpleHTMLDOM($uri)
|
||||
or returnServerError('No results for Elsevier journal ' . $this->getInput('j'));
|
||||
|
||||
foreach($html->find('.pod-listing') as $article) {
|
||||
$item = array();
|
||||
$item['uri'] = $article->find('.pod-listing-header>a', 0)->getAttribute('href') . '?np=y';
|
||||
$item['title'] = $article->find('.pod-listing-header>a', 0)->plaintext;
|
||||
$item['author'] = $this->ExtractArticleName($article);
|
||||
$item['timestamp'] = $this->ExtractArticleTimestamp($article);
|
||||
$item['content'] = $this->ExtractArticleContent($article);
|
||||
$item['author'] = $this->extractArticleName($article);
|
||||
$item['timestamp'] = $this->extractArticleTimestamp($article);
|
||||
$item['content'] = $this->extractArticleContent($article);
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
@@ -8,23 +8,30 @@ class EstCeQuonMetEnProdBridge extends BridgeAbstract {
|
||||
const DESCRIPTION = 'Should we put a website in production today? (French)';
|
||||
|
||||
public function collectData(){
|
||||
function ExtractFromDelimiters($string, $start, $end) {
|
||||
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;
|
||||
}
|
||||
|
||||
$html = getSimpleHTMLDOM($this->getURI()) or returnServerError('Could not request EstCeQuonMetEnProd: '.$this->getURI());
|
||||
return false;
|
||||
}
|
||||
|
||||
$html = getSimpleHTMLDOM($this->getURI())
|
||||
or returnServerError('Could not request EstCeQuonMetEnProd: ' . $this->getURI());
|
||||
|
||||
$item = array();
|
||||
$item['uri'] = $this->getURI() . '#' . date('Y-m-d');
|
||||
$item['title'] = $this->getName();
|
||||
$item['author'] = 'Nicolas Hoffmann';
|
||||
$item['timestamp'] = strtotime('today midnight');
|
||||
$item['content'] = str_replace('src="/', 'src="'.$this->getURI(), trim(ExtractFromDelimiters($html->outertext, '<body role="document">', '<br /><br />')));
|
||||
$item['content'] = str_replace(
|
||||
'src="/',
|
||||
'src="' . $this->getURI(),
|
||||
trim(extractFromDelimiters($html->outertext, '<body role="document">', '<br /><br />'))
|
||||
);
|
||||
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
83
bridges/EtsyBridge.php
Normal file
83
bridges/EtsyBridge.php
Normal file
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
class EtsyBridge extends BridgeAbstract {
|
||||
|
||||
const NAME = 'Etsy search';
|
||||
const URI = 'https://www.etsy.com';
|
||||
const DESCRIPTION = 'Returns feeds for search results';
|
||||
const MAINTAINER = 'logmanoriginal';
|
||||
const PARAMETERS = array(
|
||||
array(
|
||||
'query' => array(
|
||||
'name' => 'Search query',
|
||||
'type' => 'text',
|
||||
'required' => true,
|
||||
'title' => 'Insert your search term here',
|
||||
'exampleValue' => 'Enter your search term'
|
||||
),
|
||||
'queryextension' => array(
|
||||
'name' => 'Query extension',
|
||||
'type' => 'text',
|
||||
'requied' => false,
|
||||
'title' => 'Insert additional query parts here
|
||||
(anything after ?search=<your search query>)',
|
||||
'exampleValue' => '&explicit=1&locationQuery=2921044'
|
||||
),
|
||||
'showimage' => array(
|
||||
'name' => 'Show image in content',
|
||||
'type' => 'checkbox',
|
||||
'requrired' => false,
|
||||
'title' => 'Activate to show the image in the content',
|
||||
'defaultValue' => false
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
public function collectData(){
|
||||
$html = getSimpleHTMLDOM($this->getURI())
|
||||
or returnServerError('Failed to receive ' . $this->getURI());
|
||||
|
||||
$results = $html->find('div.block-grid-item');
|
||||
|
||||
foreach($results as $result) {
|
||||
// Skip banner cards (ads for categories)
|
||||
if($result->find('a.banner-card'))
|
||||
continue;
|
||||
|
||||
$item = array();
|
||||
|
||||
$item['title'] = $result->find('a', 0)->title;
|
||||
$item['uri'] = $result->find('a', 0)->href;
|
||||
$item['author'] = $result->find('div.card-shop-name', 0)->plaintext;
|
||||
|
||||
$item['content'] = '<p>'
|
||||
. $result->find('div.card-price', 0)->plaintext
|
||||
. '</p><p>'
|
||||
. $result->find('div.card-title', 0)->plaintext
|
||||
. '</p>';
|
||||
|
||||
$image = $result->find('img.placeholder', 0)->src;
|
||||
|
||||
if($this->getInput('showimage')) {
|
||||
$item['content'] .= '<img src="' . $image . '">';
|
||||
}
|
||||
|
||||
$item['enclosures'] = array($image);
|
||||
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
public function getURI(){
|
||||
if(!is_null($this->getInput('query'))) {
|
||||
$uri = self::URI . '/search?q=' . urlencode($this->getInput('query'));
|
||||
|
||||
if(!is_null($this->getInput('queryextension'))) {
|
||||
$uri .= $this->getInput('queryextension');
|
||||
}
|
||||
|
||||
return $uri;
|
||||
}
|
||||
|
||||
return parent::getURI();
|
||||
}
|
||||
}
|
281
bridges/FB2Bridge.php
Normal file
281
bridges/FB2Bridge.php
Normal file
@@ -0,0 +1,281 @@
|
||||
<?php
|
||||
class FB2Bridge extends BridgeAbstract {
|
||||
|
||||
const MAINTAINER = 'teromene';
|
||||
const NAME = 'Facebook Alternate';
|
||||
const URI = 'https://www.facebook.com/';
|
||||
const CACHE_TIMEOUT = 1000;
|
||||
const DESCRIPTION = 'Input a page title or a profile log. For a profile log,
|
||||
please insert the parameter as follow : myExamplePage/132621766841117';
|
||||
|
||||
const PARAMETERS = array( array(
|
||||
'u' => array(
|
||||
'name' => 'Username',
|
||||
'required' => true
|
||||
)
|
||||
));
|
||||
|
||||
public function collectData(){
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
//Utility function for cleaning a Facebook link
|
||||
$unescape_fb_link = function($matches){
|
||||
if(is_array($matches) && count($matches) > 1) {
|
||||
$link = $matches[1];
|
||||
if(strpos($link, '/') === 0)
|
||||
$link = self::URI . $link . '"';
|
||||
if(strpos($link, 'facebook.com/l.php?u=') !== false)
|
||||
$link = urldecode(extractFromDelimiters($link, 'facebook.com/l.php?u=', '&'));
|
||||
return ' href="' . $link . '"';
|
||||
}
|
||||
};
|
||||
|
||||
//Utility function for converting facebook emoticons
|
||||
$unescape_fb_emote = function($matches){
|
||||
static $facebook_emoticons = array(
|
||||
'smile' => ':)',
|
||||
'frown' => ':(',
|
||||
'tongue' => ':P',
|
||||
'grin' => ':D',
|
||||
'gasp' => ':O',
|
||||
'wink' => ';)',
|
||||
'pacman' => ':<',
|
||||
'grumpy' => '>_<',
|
||||
'unsure' => ':/',
|
||||
'cry' => ':\'(',
|
||||
'kiki' => '^_^',
|
||||
'glasses' => '8-)',
|
||||
'sunglasses' => 'B-)',
|
||||
'heart' => '<3',
|
||||
'devil' => ']:D',
|
||||
'angel' => '0:)',
|
||||
'squint' => '-_-',
|
||||
'confused' => 'o_O',
|
||||
'upset' => 'xD',
|
||||
'colonthree' => ':3',
|
||||
'like' => '👍');
|
||||
$len = count($matches);
|
||||
if ($len > 1)
|
||||
for ($i = 1; $i < $len; $i++)
|
||||
foreach ($facebook_emoticons as $name => $emote)
|
||||
if ($matches[$i] === $name)
|
||||
return $emote;
|
||||
return $matches[0];
|
||||
};
|
||||
|
||||
if($this->getInput('u') !== null) {
|
||||
$page = 'https://touch.facebook.com/' . $this->getInput('u');
|
||||
$cookies = $this->getCookies($page);
|
||||
$pageID = $this->getPageID($page, $cookies);
|
||||
|
||||
if($pageID === null) {
|
||||
echo <<<EOD
|
||||
Unable to get the page id. You should consider getting the ID by hand, then importing it into FB2Bridge
|
||||
EOD;
|
||||
die();
|
||||
} elseif($pageID == -1) {
|
||||
echo <<<EOD
|
||||
This page is not accessible without being logged in.
|
||||
EOD;
|
||||
die();
|
||||
}
|
||||
}
|
||||
|
||||
//Build the string for the first request
|
||||
$requestString = 'https://touch.facebook.com/pages_reaction_units/more/?page_id='
|
||||
. $pageID
|
||||
. '&cursor={"card_id"%3A"videos"%2C"has_next_page"%3Atrue}&surface=mobile_page_home&unit_count=8';
|
||||
|
||||
$fileContent = file_get_contents($requestString);
|
||||
|
||||
$articleIndex = 0;
|
||||
$maxArticle = 3;
|
||||
|
||||
$html = $this->buildContent($fileContent);
|
||||
$author = $this->getInput('u');
|
||||
|
||||
foreach($html->find("article") as $content) {
|
||||
|
||||
$item = array();
|
||||
|
||||
$item['uri'] = "http://touch.facebook.com"
|
||||
. $content->find("div[class='_52jc _5qc4 _24u0 _36xo']", 0)->find("a", 0)->getAttribute("href");
|
||||
|
||||
if($content->find("header", 0) !== null) {
|
||||
$content->find("header", 0)->innertext = "";
|
||||
}
|
||||
|
||||
if($content->find("footer", 0) !== null) {
|
||||
$content->find("footer", 0)->innertext = "";
|
||||
}
|
||||
|
||||
//Remove html nodes, keep only img, links, basic formatting
|
||||
$content = strip_tags($content, '<a><img><i><u><br><p>');
|
||||
|
||||
//Adapt link hrefs: convert relative links into absolute links and bypass external link redirection
|
||||
$content = preg_replace_callback('/ href=\"([^"]+)\"/i', $unescape_fb_link, $content);
|
||||
|
||||
//Clean useless html tag properties and fix link closing tags
|
||||
foreach (array(
|
||||
'onmouseover',
|
||||
'onclick',
|
||||
'target',
|
||||
'ajaxify',
|
||||
'tabindex',
|
||||
'class',
|
||||
'style',
|
||||
'data-[^=]*',
|
||||
'aria-[^=]*',
|
||||
'role',
|
||||
'rel',
|
||||
'id') as $property_name)
|
||||
$content = preg_replace('/ ' . $property_name . '=\"[^"]*\"/i', '', $content);
|
||||
$content = preg_replace('/<\/a [^>]+>/i', '</a>', $content);
|
||||
|
||||
//Convert textual representation of emoticons eg
|
||||
// "<i><u>smile emoticon</u></i>" back to ASCII emoticons eg ":)"
|
||||
$content = preg_replace_callback('/<i><u>([^ <>]+) ([^<>]+)<\/u><\/i>/i', $unescape_fb_emote, $content);
|
||||
|
||||
$item['content'] = $content;
|
||||
|
||||
$title = $author;
|
||||
if (strlen($title) > 24)
|
||||
$title = substr($title, 0, strpos(wordwrap($title, 24), "\n")) . '...';
|
||||
$title = $title . ' | ' . strip_tags($content);
|
||||
if (strlen($title) > 64)
|
||||
$title = substr($title, 0, strpos(wordwrap($title, 64), "\n")) . '...';
|
||||
|
||||
$item['title'] = $title;
|
||||
$item['author'] = $author;
|
||||
|
||||
array_push($this->items, $item);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Currently not used. Is used to get more than only 3 elements, as they appear on another page.
|
||||
private function computeNextLink($string, $pageID){
|
||||
|
||||
$regex = implode(
|
||||
'',
|
||||
array(
|
||||
"/timeline_unit",
|
||||
"\\\\\\\\u00253A1",
|
||||
"\\\\\\\\u00253A([0-9]*)",
|
||||
"\\\\\\\\u00253A([0-9]*)",
|
||||
"\\\\\\\\u00253A([0-9]*)",
|
||||
"\\\\\\\\u00253A([0-9]*)/"
|
||||
)
|
||||
);
|
||||
|
||||
preg_match($regex, $string, $result);
|
||||
|
||||
return implode(
|
||||
'',
|
||||
array(
|
||||
"https://touch.facebook.com/pages_reaction_units/more/?page_id=",
|
||||
$pageID,
|
||||
"&cursor=%7B%22timeline_cursor%22%3A%22timeline_unit%3A1%3A",
|
||||
$result[1],
|
||||
"%3A",
|
||||
$result[2],
|
||||
"%3A",
|
||||
$result[3],
|
||||
"%3A",
|
||||
$result[4],
|
||||
"%22%2C%22timeline_section_cursor%22%3A%7B%7D%2C%22",
|
||||
"has_next_page%22%3Atrue%7D&surface=mobile_page_home&unit_count=3"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
//Builds the HTML from the encoded JS that Facebook provides.
|
||||
private function buildContent($pageContent){
|
||||
|
||||
$regex = "/\\\"html\\\":\\\"(.*?)\\\",\\\"replace/";
|
||||
preg_match($regex, $pageContent, $result);
|
||||
|
||||
return str_get_html(html_entity_decode(json_decode('"' . $result[1] . '"')));
|
||||
}
|
||||
|
||||
|
||||
//Builds the cookie from the page, as Facebook sometimes refuses to give
|
||||
//the page if no cookie is provided.
|
||||
private function getCookies($pageURL){
|
||||
|
||||
$ctx = stream_context_create(array(
|
||||
'http' => array(
|
||||
'user_agent' => "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:46.0) Gecko/20100101 Firefox/46.0",
|
||||
'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'
|
||||
)
|
||||
)
|
||||
);
|
||||
$a = file_get_contents($pageURL, 0, $ctx);
|
||||
|
||||
//First request to get the cookie
|
||||
$cookies = "";
|
||||
foreach($http_response_header as $hdr) {
|
||||
if(strpos($hdr, "Set-Cookie") !== false) {
|
||||
$cLine = explode(":", $hdr)[1];
|
||||
$cLine = explode(";", $cLine)[0];
|
||||
$cookies .= ";" . $cLine;
|
||||
}
|
||||
}
|
||||
|
||||
return substr($cookies, 1);
|
||||
}
|
||||
|
||||
//Get the page ID from the Facebook page.
|
||||
private function getPageID($page, $cookies){
|
||||
|
||||
$context = stream_context_create(array(
|
||||
'http' => array(
|
||||
'user_agent' => "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:46.0) Gecko/20100101 Firefox/46.0",
|
||||
'header' => 'Cookie: ' . $cookies
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
$pageContent = file_get_contents($page, 0, $context);
|
||||
|
||||
if(strpos($pageContent, "signup-button") != false) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
//Get the page ID if we don't have a captcha
|
||||
$regex = "/page_id=([0-9]*)&/";
|
||||
preg_match($regex, $pageContent, $matches);
|
||||
|
||||
if(count($matches) > 0) {
|
||||
return $matches[1];
|
||||
}
|
||||
|
||||
//Get the page ID if we do have a captcha
|
||||
$regex = "/\"pageID\":\"([0-9]*)\"/";
|
||||
preg_match($regex, $pageContent, $matches);
|
||||
|
||||
return $matches[1];
|
||||
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return (isset($this->name) ? $this->name . ' - ' : '') . 'Facebook Bridge';
|
||||
}
|
||||
|
||||
public function getURI(){
|
||||
return 'http://facebook.com';
|
||||
}
|
||||
|
||||
public function getCacheDuration(){
|
||||
return 60 * 60 * 3; // 5 minutes
|
||||
}
|
||||
}
|
@@ -1,16 +1,28 @@
|
||||
<?php
|
||||
class FacebookBridge extends BridgeAbstract {
|
||||
|
||||
const MAINTAINER = "teromene";
|
||||
const NAME = "Facebook";
|
||||
const URI = "https://www.facebook.com/";
|
||||
const MAINTAINER = 'teromene';
|
||||
const NAME = 'Facebook';
|
||||
const URI = 'https://www.facebook.com/';
|
||||
const CACHE_TIMEOUT = 300; // 5min
|
||||
const DESCRIPTION = "Input a page title or a profile log. For a profile log, please insert the parameter as follow : myExamplePage/132621766841117";
|
||||
const DESCRIPTION = 'Input a page title or a profile log. For a profile log,
|
||||
please insert the parameter as follow : myExamplePage/132621766841117';
|
||||
|
||||
const PARAMETERS = array( array(
|
||||
'u' => array(
|
||||
'name' => 'Username',
|
||||
'required' => true
|
||||
),
|
||||
'media_type' => array(
|
||||
'name' => 'Media type',
|
||||
'type' => 'list',
|
||||
'required' => false,
|
||||
'values' => array(
|
||||
'All' => 'all',
|
||||
'Video' => 'video',
|
||||
'No Video' => 'novideo'
|
||||
),
|
||||
'defaultValue' => 'all'
|
||||
)
|
||||
));
|
||||
|
||||
@@ -19,12 +31,14 @@ class FacebookBridge extends BridgeAbstract{
|
||||
public function collectData(){
|
||||
|
||||
//Extract a string using start and end delimiters
|
||||
function ExtractFromDelimiters($string, $start, $end) {
|
||||
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;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//Utility function for cleaning a Facebook link
|
||||
@@ -32,9 +46,9 @@ class FacebookBridge extends BridgeAbstract{
|
||||
if(is_array($matches) && count($matches) > 1) {
|
||||
$link = $matches[1];
|
||||
if(strpos($link, '/') === 0)
|
||||
$link = self::URI.$link.'"';
|
||||
$link = self::URI . $link;
|
||||
if(strpos($link, 'facebook.com/l.php?u=') !== false)
|
||||
$link = urldecode(ExtractFromDelimiters($link, 'facebook.com/l.php?u=', '&'));
|
||||
$link = urldecode(extractFromDelimiters($link, 'facebook.com/l.php?u=', '&'));
|
||||
return ' href="' . $link . '"';
|
||||
}
|
||||
};
|
||||
@@ -75,26 +89,26 @@ class FacebookBridge extends BridgeAbstract{
|
||||
$html = null;
|
||||
|
||||
//Handle captcha response sent by the viewer
|
||||
if (isset($_POST['captcha_response']))
|
||||
{
|
||||
if (isset($_POST['captcha_response'])) {
|
||||
if (session_status() == PHP_SESSION_NONE)
|
||||
session_start();
|
||||
if (isset($_SESSION['captcha_fields'], $_SESSION['captcha_action']))
|
||||
{
|
||||
if (isset($_SESSION['captcha_fields'], $_SESSION['captcha_action'])) {
|
||||
$captcha_action = $_SESSION['captcha_action'];
|
||||
$captcha_fields = $_SESSION['captcha_fields'];
|
||||
$captcha_fields['captcha_response'] = preg_replace("/[^a-zA-Z0-9]+/", "", $_POST['captcha_response']);
|
||||
$http_options = array(
|
||||
'http' => array(
|
||||
'method' => 'POST',
|
||||
'user_agent'=> ini_get('user_agent'),
|
||||
'header'=>array("Content-type: application/x-www-form-urlencoded\r\nReferer: $captcha_action\r\nCookie: noscript=1\r\n"),
|
||||
'content' => http_build_query($captcha_fields),
|
||||
),
|
||||
|
||||
$header = array("Content-type:
|
||||
application/x-www-form-urlencoded\r\nReferer: $captcha_action\r\nCookie: noscript=1\r\n");
|
||||
$opts = array(
|
||||
CURLOPT_POST => 1,
|
||||
CURLOPT_POSTFIELDS => http_build_query($captcha_fields)
|
||||
);
|
||||
$context = stream_context_create($http_options);
|
||||
$html = getContents($captcha_action, false, $context);
|
||||
if ($html === FALSE) { returnServerError('Failed to submit captcha response back to Facebook'); }
|
||||
|
||||
$html = getContents($captcha_action, $header, $opts);
|
||||
|
||||
if($html === false) {
|
||||
returnServerError('Failed to submit captcha response back to Facebook');
|
||||
}
|
||||
unset($_SESSION['captcha_fields']);
|
||||
$html = str_get_html($html);
|
||||
}
|
||||
@@ -104,19 +118,25 @@ class FacebookBridge extends BridgeAbstract{
|
||||
|
||||
//Retrieve page contents
|
||||
if(is_null($html)) {
|
||||
$header = array('Accept-Language: ' . getEnv('HTTP_ACCEPT_LANGUAGE') . "\r\n");
|
||||
|
||||
// First character cannot be a forward slash
|
||||
if(strpos($this->getInput('u'), "/") === 0) {
|
||||
returnClientError('Remove leading slash "/" from the username!');
|
||||
}
|
||||
|
||||
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)
|
||||
or returnServerError('No results for this query.');
|
||||
} else {
|
||||
$html = getSimpleHTMLDOM(self::URI.'pages/'.$this->getInput('u').'?_fb_noscript=1')
|
||||
$html = getSimpleHTMLDOM(self::URI . 'pages/' . $this->getInput('u') . '?_fb_noscript=1', $header)
|
||||
or returnServerError('No results for this query.');
|
||||
}
|
||||
}
|
||||
|
||||
//Handle captcha form?
|
||||
$captcha = $html->find('div.captcha_interstitial', 0);
|
||||
if (!is_null($captcha))
|
||||
{
|
||||
if (!is_null($captcha)) {
|
||||
//Save form for submitting after getting captcha response
|
||||
if (session_status() == PHP_SESSION_NONE)
|
||||
session_start();
|
||||
@@ -124,57 +144,119 @@ class FacebookBridge extends BridgeAbstract{
|
||||
foreach ($captcha->find('input, button') as $input)
|
||||
$captcha_fields[$input->name] = $input->value;
|
||||
$_SESSION['captcha_fields'] = $captcha_fields;
|
||||
$_SESSION['captcha_action'] = self::URI.$captcha->find('form', 0)->action;
|
||||
$_SESSION['captcha_action'] = $captcha->find('form', 0)->action;
|
||||
|
||||
//Show captcha filling form to the viewer, proxying the captcha image
|
||||
$img = base64_encode(getContents($captcha->find('img', 0)->src));
|
||||
header('HTTP/1.1 500 '.Http::getMessageForCode(500));
|
||||
http_response_code(500);
|
||||
header('Content-Type: text/html');
|
||||
die('<form method="post" action="?'.$_SERVER['QUERY_STRING'].'">'
|
||||
.'<h2>Facebook captcha challenge</h2>'
|
||||
.'<p>Unfortunately, rss-bridge cannot fetch the requested page.<br />'
|
||||
.'Facebook wants rss-bridge to resolve the following captcha:</p>'
|
||||
.'<p><img src="data:image/png;base64,'.$img.'" /></p>'
|
||||
.'<p><b>Response:</b> <input name="captcha_response" placeholder="please fill in" />'
|
||||
.'<input type="submit" value="Submit!" /></p>'
|
||||
.'</form>');
|
||||
$message = <<<EOD
|
||||
<form method="post" action="?{$_SERVER['QUERY_STRING']}">
|
||||
<h2>Facebook captcha challenge</h2>
|
||||
<p>Unfortunately, rss-bridge cannot fetch the requested page.<br />
|
||||
Facebook wants rss-bridge to resolve the following captcha:</p>
|
||||
<p><img src="data:image/png;base64,{$img}" /></p>
|
||||
<p><b>Response:</b> <input name="captcha_response" placeholder="please fill in" />
|
||||
<input type="submit" value="Submit!" /></p>
|
||||
</form>
|
||||
EOD;
|
||||
die($message);
|
||||
}
|
||||
|
||||
//No captcha? We can carry on retrieving page contents :)
|
||||
$element = $html->find('#pagelet_timeline_main_column')[0]->children(0)->children(0)->children(0)->next_sibling()->children(0);
|
||||
$element = $html
|
||||
->find('#pagelet_timeline_main_column')[0]
|
||||
->children(0)
|
||||
->children(0)
|
||||
->children(0)
|
||||
->next_sibling()
|
||||
->children(0);
|
||||
|
||||
if(isset($element)) {
|
||||
|
||||
$author = str_replace(' | Facebook', '', $html->find('title#pageTitle', 0)->innertext);
|
||||
$profilePic = 'https://graph.facebook.com/'.$this->getInput('u').'/picture?width=200&height=200';
|
||||
$profilePic = 'https://graph.facebook.com/'
|
||||
. $this->getInput('u')
|
||||
. '/picture?width=200&height=200';
|
||||
|
||||
$this->authorName = $author;
|
||||
|
||||
foreach($element->children() as $post) {
|
||||
foreach($element->children() as $cell) {
|
||||
// Manage summary posts
|
||||
if(strpos($cell->class, '_3xaf') !== false) {
|
||||
$posts = $cell->children();
|
||||
} else {
|
||||
$posts = array($cell);
|
||||
}
|
||||
|
||||
foreach($posts as $post) {
|
||||
// Check media type
|
||||
switch($this->getInput('media_type')) {
|
||||
case 'all': break;
|
||||
case 'video':
|
||||
if(empty($post->find('[aria-label=Video]'))) continue 2;
|
||||
break;
|
||||
case 'novideo':
|
||||
if(!empty($post->find('[aria-label=Video]'))) continue 2;
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
$item = array();
|
||||
|
||||
if(count($post->find('abbr')) > 0) {
|
||||
|
||||
//Retrieve post contents
|
||||
$content = preg_replace('/(?i)><div class=\"clearfix([^>]+)>(.+?)div\ class=\"userContent\"/i', '', $post);
|
||||
$content = preg_replace('/(?i)><div class=\"_59tj([^>]+)>(.+?)<\/div><\/div><a/i', '', $content);
|
||||
$content = preg_replace('/(?i)><div class=\"_3dp([^>]+)>(.+?)div\ class=\"[^u]+userContent\"/i', '', $content);
|
||||
$content = preg_replace('/(?i)><div class=\"_4l5([^>]+)>(.+?)<\/div>/i', '', $content);
|
||||
$content = preg_replace(
|
||||
'/(?i)><div class=\"clearfix([^>]+)>(.+?)div\ class=\"userContent\"/i',
|
||||
'',
|
||||
$post);
|
||||
|
||||
$content = preg_replace(
|
||||
'/(?i)><div class=\"_59tj([^>]+)>(.+?)<\/div><\/div><a/i',
|
||||
'',
|
||||
$content);
|
||||
|
||||
$content = preg_replace(
|
||||
'/(?i)><div class=\"_3dp([^>]+)>(.+?)div\ class=\"[^u]+userContent\"/i',
|
||||
'',
|
||||
$content);
|
||||
|
||||
$content = preg_replace(
|
||||
'/(?i)><div class=\"_4l5([^>]+)>(.+?)<\/div>/i',
|
||||
'',
|
||||
$content);
|
||||
|
||||
//Remove html nodes, keep only img, links, basic formatting
|
||||
$content = strip_tags($content,'<a><img><i><u>');
|
||||
$content = strip_tags($content, '<a><img><i><u><br><p>');
|
||||
|
||||
//Adapt link hrefs: convert relative links into absolute links and bypass external link redirection
|
||||
$content = preg_replace_callback('/ href=\"([^"]+)\"/i', $unescape_fb_link, $content);
|
||||
|
||||
//Clean useless html tag properties and fix link closing tags
|
||||
foreach (array('onmouseover', 'onclick', 'target', 'ajaxify', 'tabindex',
|
||||
'class', 'style', 'data-[^=]*', 'aria-[^=]*', 'role', 'rel', 'id') as $property_name)
|
||||
foreach (array(
|
||||
'onmouseover',
|
||||
'onclick',
|
||||
'target',
|
||||
'ajaxify',
|
||||
'tabindex',
|
||||
'class',
|
||||
'style',
|
||||
'data-[^=]*',
|
||||
'aria-[^=]*',
|
||||
'role',
|
||||
'rel',
|
||||
'id') as $property_name)
|
||||
$content = preg_replace('/ ' . $property_name . '=\"[^"]*\"/i', '', $content);
|
||||
$content = preg_replace('/<\/a [^>]+>/i', '</a>', $content);
|
||||
|
||||
//Convert textual representation of emoticons eg "<i><u>smile emoticon</u></i>" back to ASCII emoticons eg ":)"
|
||||
$content = preg_replace_callback('/<i><u>([^ <>]+) ([^<>]+)<\/u><\/i>/i', $unescape_fb_emote, $content);
|
||||
//Convert textual representation of emoticons eg
|
||||
//"<i><u>smile emoticon</u></i>" back to ASCII emoticons eg ":)"
|
||||
$content = preg_replace_callback(
|
||||
'/<i><u>([^ <>]+) ([^<>]+)<\/u><\/i>/i',
|
||||
$unescape_fb_emote,
|
||||
$content
|
||||
);
|
||||
|
||||
//Retrieve date of the post
|
||||
$date = $post->find("abbr")[0];
|
||||
@@ -192,9 +274,11 @@ class FacebookBridge extends BridgeAbstract{
|
||||
if(strlen($title) > 64)
|
||||
$title = substr($title, 0, strpos(wordwrap($title, 64), "\n")) . '...';
|
||||
|
||||
$uri = self::URI . $post->find('abbr')[0]->parent()->getAttribute('href');
|
||||
|
||||
//Build and add final item
|
||||
$item['uri'] = self::URI.$post->find('abbr')[0]->parent()->getAttribute('href');
|
||||
$item['content'] = $content;
|
||||
$item['uri'] = htmlspecialchars_decode($uri);
|
||||
$item['content'] = htmlspecialchars_decode($content);
|
||||
$item['title'] = $title;
|
||||
$item['author'] = $author;
|
||||
$item['timestamp'] = $date;
|
||||
@@ -203,8 +287,14 @@ class FacebookBridge extends BridgeAbstract{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return (isset($this->authorName) ? $this->authorName.' - ' : '').'Facebook Bridge';
|
||||
if(!empty($this->authorName)) {
|
||||
return isset($this->extraInfos['name']) ? $this->extraInfos['name'] : $this->authorName
|
||||
. ' - Facebook Bridge';
|
||||
}
|
||||
|
||||
return parent::getName();
|
||||
}
|
||||
}
|
||||
|
@@ -1,14 +1,15 @@
|
||||
<?php
|
||||
class FierPandaBridge extends BridgeAbstract {
|
||||
|
||||
const MAINTAINER = "snroki";
|
||||
const NAME = "Fier Panda Bridge";
|
||||
const URI = "http://www.fier-panda.fr/";
|
||||
const MAINTAINER = 'snroki';
|
||||
const NAME = 'Fier Panda Bridge';
|
||||
const URI = 'http://www.fier-panda.fr/';
|
||||
const CACHE_TIMEOUT = 21600; // 6h
|
||||
const DESCRIPTION = "Returns latest articles from Fier Panda.";
|
||||
const DESCRIPTION = 'Returns latest articles from Fier Panda.';
|
||||
|
||||
public function collectData(){
|
||||
$html = getSimpleHTMLDOM(self::URI) or returnServerError('Could not request Fier Panda.');
|
||||
$html = getSimpleHTMLDOM(self::URI)
|
||||
or returnServerError('Could not request Fier Panda.');
|
||||
|
||||
foreach($html->find('div.container-content article') as $element) {
|
||||
$item = array();
|
||||
|
77
bridges/FilterBridge.php
Normal file
77
bridges/FilterBridge.php
Normal file
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
class FilterBridge extends FeedExpander {
|
||||
|
||||
const MAINTAINER = 'Frenzie';
|
||||
const NAME = 'Filter';
|
||||
const CACHE_TIMEOUT = 3600; // 1h
|
||||
const DESCRIPTION = 'Filters a feed of your choice';
|
||||
|
||||
const PARAMETERS = array(array(
|
||||
'url' => array(
|
||||
'name' => 'Feed URL',
|
||||
'required' => true,
|
||||
),
|
||||
'filter' => array(
|
||||
'name' => 'Filter item title (regular expression)',
|
||||
'required' => false,
|
||||
),
|
||||
'filter_type' => array(
|
||||
'name' => 'Filter type',
|
||||
'type' => 'list',
|
||||
'required' => false,
|
||||
'values' => array(
|
||||
'Permit' => 'permit',
|
||||
'Block' => 'block',
|
||||
),
|
||||
'defaultValue' => 'permit',
|
||||
),
|
||||
));
|
||||
|
||||
protected function parseItem($newItem){
|
||||
$item = parent::parseItem($newItem);
|
||||
|
||||
switch(true) {
|
||||
case $this->getFilterType() === 'permit':
|
||||
if (preg_match($this->getFilter(), $item['title'])) {
|
||||
return $item;
|
||||
}
|
||||
break;
|
||||
case $this->getFilterType() === 'block':
|
||||
if (!preg_match($this->getFilter(), $item['title'])) {
|
||||
return $item;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function getFilter(){
|
||||
return '/' . $this->getInput('filter') . '/';
|
||||
}
|
||||
|
||||
protected function getFilterType(){
|
||||
return $this->getInput('filter_type');
|
||||
}
|
||||
|
||||
public function getURI(){
|
||||
$url = $this->getInput('url');
|
||||
|
||||
if(empty($url)) {
|
||||
$url = parent::getURI();
|
||||
}
|
||||
return $url;
|
||||
}
|
||||
|
||||
public function collectData(){
|
||||
if($this->getInput('url') && substr($this->getInput('url'), 0, strlen('http')) !== 'http') {
|
||||
// just in case someone find a way to access local files by playing with the url
|
||||
returnClientError('The url parameter must either refer to http or https protocol.');
|
||||
}
|
||||
try{
|
||||
$this->collectExpandableDatas($this->getURI());
|
||||
} catch (HttpException $e) {
|
||||
$this->collectExpandableDatas($this->getURI());
|
||||
}
|
||||
}
|
||||
}
|
120
bridges/FlickrBridge.php
Normal file
120
bridges/FlickrBridge.php
Normal file
@@ -0,0 +1,120 @@
|
||||
<?php
|
||||
|
||||
/* This is a mashup of FlickrExploreBridge by sebsauvage and FlickrTagBridge
|
||||
* by erwang, providing the functionality of both in one.
|
||||
*/
|
||||
class FlickrBridge extends BridgeAbstract {
|
||||
|
||||
const MAINTAINER = 'logmanoriginal';
|
||||
const NAME = 'Flickr Bridge';
|
||||
const URI = 'https://www.flickr.com/';
|
||||
const CACHE_TIMEOUT = 21600; // 6 hours
|
||||
const DESCRIPTION = 'Returns images from Flickr';
|
||||
|
||||
const PARAMETERS = array(
|
||||
'Explore' => array(),
|
||||
'By keyword' => array(
|
||||
'q' => array(
|
||||
'name' => 'Keyword',
|
||||
'type' => 'text',
|
||||
'required' => true,
|
||||
'title' => 'Insert keyword',
|
||||
'exampleValue' => 'bird'
|
||||
)
|
||||
),
|
||||
'By username' => array(
|
||||
'u' => array(
|
||||
'name' => 'Username',
|
||||
'type' => 'text',
|
||||
'required' => true,
|
||||
'title' => 'Insert username (as shown in the address bar)',
|
||||
'exampleValue' => 'flickr'
|
||||
)
|
||||
),
|
||||
);
|
||||
|
||||
public function collectData(){
|
||||
switch($this->queriedContext) {
|
||||
case 'Explore':
|
||||
$key = 'photos';
|
||||
$html = getSimpleHTMLDOM(self::URI . 'explore')
|
||||
or returnServerError('Could not request Flickr.');
|
||||
break;
|
||||
case 'By keyword':
|
||||
$key = 'photos';
|
||||
$html = getSimpleHTMLDOM(self::URI . 'search/?q=' . urlencode($this->getInput('q')) . '&s=rec')
|
||||
or returnServerError('No results for this query.');
|
||||
break;
|
||||
case 'By username':
|
||||
$key = 'photoPageList';
|
||||
$html = getSimpleHTMLDOM(self::URI . 'photos/' . urlencode($this->getInput('u')))
|
||||
or returnServerError('Requested username can\'t be found.');
|
||||
break;
|
||||
default:
|
||||
returnClientError('Invalid context: ' . $this->queriedContext);
|
||||
}
|
||||
|
||||
// Find SCRIPT containing JSON data
|
||||
$model = $html->find('.modelExport', 0);
|
||||
$model_text = $model->innertext;
|
||||
|
||||
// Find start and end of JSON data
|
||||
$start = strpos($model_text, 'modelExport:') + strlen('modelExport:');
|
||||
$end = strpos($model_text, 'auth:') - strlen('auth:');
|
||||
|
||||
// Dissect JSON data and remove trailing comma
|
||||
$model_text = trim(substr($model_text, $start, $end - $start));
|
||||
$model_text = substr($model_text, 0, strlen($model_text) - 1);
|
||||
|
||||
$model_json = json_decode($model_text, true);
|
||||
|
||||
foreach($html->find('.photo-list-photo-view') as $element) {
|
||||
// Get the styles
|
||||
$style = explode(';', $element->style);
|
||||
|
||||
// Get the background-image style
|
||||
$backgroundImage = explode(':', end($style));
|
||||
|
||||
// URI type : url(//cX.staticflickr.com/X/XXXXX/XXXXXXXXX.jpg)
|
||||
$imageURI = trim(str_replace(['url(', ')'], '', end($backgroundImage)));
|
||||
|
||||
// Get the image ID
|
||||
$imageURIs = explode('_', basename($imageURI));
|
||||
$imageID = reset($imageURIs);
|
||||
|
||||
// Use JSON data to build items
|
||||
foreach(reset($model_json)[0][$key]['_data'] as $element) {
|
||||
if($element['id'] === $imageID) {
|
||||
$item = array();
|
||||
|
||||
/* Author name depends on scope. On a keyword search the
|
||||
* author is part of the picture data. On a username search
|
||||
* the author is part of the owner data.
|
||||
*/
|
||||
if(array_key_exists('username', $element)) {
|
||||
$item['author'] = $element['username'];
|
||||
} elseif (array_key_exists('owner', reset($model_json)[0])) {
|
||||
$item['author'] = reset($model_json)[0]['owner']['username'];
|
||||
}
|
||||
|
||||
$item['title'] = (array_key_exists('title', $element) ? $element['title'] : 'Untitled');
|
||||
$item['uri'] = self::URI . 'photo.gne?id=' . $imageID;
|
||||
|
||||
$description = (array_key_exists('description', $element) ? $element['description'] : '');
|
||||
|
||||
$item['content'] = '<a href="'
|
||||
. $item['uri']
|
||||
. '"><img src="'
|
||||
. $imageURI
|
||||
. '" /></a><br><p>'
|
||||
. $description
|
||||
. '</p>';
|
||||
|
||||
$this->items[] = $item;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,42 +0,0 @@
|
||||
<?php
|
||||
class FlickrExploreBridge extends BridgeAbstract{
|
||||
|
||||
const MAINTAINER = "sebsauvage";
|
||||
const NAME = "Flickr Explore";
|
||||
const URI = "https://www.flickr.com/";
|
||||
const CACHE_TIMEOUT = 21600; // 6
|
||||
const DESCRIPTION = "Returns the latest interesting images from Flickr";
|
||||
|
||||
public function collectData(){
|
||||
$html = getSimpleHTMLDOM(self::URI.'explore')
|
||||
or returnServerError('Could not request Flickr.');
|
||||
|
||||
foreach($html->find('.photo-list-photo-view') as $element) {
|
||||
// Get the styles
|
||||
$style = explode(';', $element->style);
|
||||
// Get the background-image style
|
||||
$backgroundImage = explode(':', end($style));
|
||||
// URI type : url(//cX.staticflickr.com/X/XXXXX/XXXXXXXXX.jpg)
|
||||
$imageURI = trim(str_replace(['url(', ')'], '', end($backgroundImage)));
|
||||
// Get the image ID
|
||||
$imageURIs = explode('_', basename($imageURI));
|
||||
$imageID = reset($imageURIs);
|
||||
|
||||
// Get the image JSON via Flickr API
|
||||
$imageJSON = json_decode(getContents(
|
||||
'https://api.flickr.com/services/rest/?'
|
||||
.'method=flickr.photos.getInfo&'
|
||||
.'api_key=103b574d49bd51f0e18bfe907da44a0f&'
|
||||
.'photo_id='.$imageID.'&'
|
||||
.'format=json&'
|
||||
.'nojsoncallback=1'
|
||||
)) or returnServerError('Could not request Flickr.'); // FIXME: Request time too long...
|
||||
|
||||
$item = array();
|
||||
$item['uri'] = self::URI.'photo.gne?id='.$imageID;
|
||||
$item['content'] = '<a href="' . $item['uri'] . '"><img src="' . $imageURI . '" /></a>'; // FIXME: Filter javascript ?
|
||||
$item['title'] = $imageJSON->photo->title->_content;
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,48 +0,0 @@
|
||||
<?php
|
||||
class FlickrTagBridge extends BridgeAbstract{
|
||||
|
||||
const MAINTAINER = "erwang";
|
||||
const NAME = "Flickr TagUser";
|
||||
const URI = "http://www.flickr.com/";
|
||||
const CACHE_TIMEOUT = 21600; //6h
|
||||
const DESCRIPTION = "Returns the tagged or user images from Flickr";
|
||||
|
||||
const PARAMETERS = array(
|
||||
'By keyword' => array(
|
||||
'q'=>array(
|
||||
'name'=>'keyword',
|
||||
'required'=>true
|
||||
)
|
||||
),
|
||||
|
||||
'By username' => array(
|
||||
'u'=>array(
|
||||
'name'=>'Username',
|
||||
'required'=>true
|
||||
)
|
||||
),
|
||||
);
|
||||
|
||||
public function collectData(){
|
||||
switch($this->queriedContext){
|
||||
case 'By keyword':
|
||||
$html = getSimpleHTMLDOM(self::URI.'search/?q='.urlencode($this->getInput('q')).'&s=rec')
|
||||
or returnServerError('No results for this query.');
|
||||
break;
|
||||
case 'by username':
|
||||
$html = getSimpleHTMLDOM(self::URI.'photos/'.urlencode($this->getInput('u')).'/')
|
||||
or returnServerError('Requested username can\'t be found.');
|
||||
break;
|
||||
}
|
||||
|
||||
foreach($html->find('span.photo_container') as $element) {
|
||||
$item = array();
|
||||
$item['uri'] = self::URI.$element->find('a',0)->href;
|
||||
$thumbnailUri = $element->find('img',0)->getAttribute('data-defer-src');
|
||||
$item['content'] = '<a href="' . $item['uri'] . '"><img src="' . $thumbnailUri . '" /></a>'; // FIXME: Filter javascript ?
|
||||
$item['title'] = $element->find('a',0)->title;
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,10 +1,10 @@
|
||||
<?php
|
||||
class FootitoBridge extends BridgeAbstract {
|
||||
|
||||
const MAINTAINER = "superbaillot.net";
|
||||
const NAME = "Footito";
|
||||
const URI = "http://www.footito.fr/";
|
||||
const DESCRIPTION = "Footito";
|
||||
const MAINTAINER = 'superbaillot.net';
|
||||
const NAME = 'Footito';
|
||||
const URI = 'http://www.footito.fr/';
|
||||
const DESCRIPTION = 'Footito';
|
||||
|
||||
public function collectData(){
|
||||
$html = getSimpleHTMLDOM(self::URI)
|
||||
@@ -14,15 +14,50 @@ class FootitoBridge extends BridgeAbstract{
|
||||
$item = array();
|
||||
|
||||
$content = trim($element->innertext);
|
||||
$content = str_replace("<img", "<img style='float : left;'", $content );
|
||||
$content = str_replace("class=\"logo\"", "style='float : left;'", $content );
|
||||
$content = str_replace("class=\"contenu\"", "style='margin-left : 60px;'", $content );
|
||||
$content = str_replace("class=\"responsive-comment\"", "style='border-top : 1px #DDD solid; background-color : white; padding : 10px;'", $content );
|
||||
$content = str_replace("class=\"jaime\"", "style='display : none;'", $content );
|
||||
$content = str_replace("class=\"auteur-event responsive\"", "style='display : none;'", $content );
|
||||
$content = str_replace("class=\"report-abuse-button\"", "style='display : none;'", $content );
|
||||
$content = str_replace("class=\"reaction clearfix\"", "style='margin : 10px 0px; padding : 5px; border-bottom : 1px #DDD solid;'", $content );
|
||||
$content = str_replace("class=\"infos\"", "style='font-size : 0.7em;'", $content );
|
||||
$content = str_replace(
|
||||
"<img",
|
||||
"<img style='float : left;'",
|
||||
$content );
|
||||
|
||||
$content = str_replace(
|
||||
"class=\"logo\"",
|
||||
"style='float : left;'",
|
||||
$content );
|
||||
|
||||
$content = str_replace(
|
||||
"class=\"contenu\"",
|
||||
"style='margin-left : 60px;'",
|
||||
$content );
|
||||
|
||||
$content = str_replace(
|
||||
"class=\"responsive-comment\"",
|
||||
"style='border-top : 1px #DDD solid; background-color : white; padding : 10px;'",
|
||||
$content );
|
||||
|
||||
$content = str_replace(
|
||||
"class=\"jaime\"",
|
||||
"style='display : none;'",
|
||||
$content );
|
||||
|
||||
$content = str_replace(
|
||||
"class=\"auteur-event responsive\"",
|
||||
"style='display : none;'",
|
||||
$content );
|
||||
|
||||
$content = str_replace(
|
||||
"class=\"report-abuse-button\"",
|
||||
"style='display : none;'",
|
||||
$content );
|
||||
|
||||
$content = str_replace(
|
||||
"class=\"reaction clearfix\"",
|
||||
"style='margin : 10px 0px; padding : 5px; border-bottom : 1px #DDD solid;'",
|
||||
$content );
|
||||
|
||||
$content = str_replace(
|
||||
"class=\"infos\"",
|
||||
"style='font-size : 0.7em;'",
|
||||
$content );
|
||||
|
||||
$item['content'] = $content;
|
||||
|
||||
|
@@ -1,11 +1,11 @@
|
||||
<?php
|
||||
class FourchanBridge extends BridgeAbstract {
|
||||
|
||||
const MAINTAINER = "mitsukarenai";
|
||||
const NAME = "4chan";
|
||||
const URI = "https://boards.4chan.org/";
|
||||
const MAINTAINER = 'mitsukarenai';
|
||||
const NAME = '4chan';
|
||||
const URI = 'https://boards.4chan.org/';
|
||||
const CACHE_TIMEOUT = 300; // 5min
|
||||
const DESCRIPTION = "Returns posts from the specified thread";
|
||||
const DESCRIPTION = 'Returns posts from the specified thread';
|
||||
|
||||
const PARAMETERS = array( array(
|
||||
'c' => array(
|
||||
@@ -20,8 +20,11 @@ class FourchanBridge extends BridgeAbstract{
|
||||
));
|
||||
|
||||
public function getURI(){
|
||||
if(!is_null($this->getInput('c')) && !is_null($this->getInput('t'))) {
|
||||
return static::URI . $this->getInput('c') . '/thread/' . $this->getInput('t');
|
||||
}
|
||||
|
||||
return parent::getURI();
|
||||
}
|
||||
|
||||
public function collectData(){
|
||||
@@ -37,12 +40,14 @@ class FourchanBridge extends BridgeAbstract{
|
||||
$item['author'] = $element->find('span.name', 0)->plaintext;
|
||||
|
||||
$file = $element->find('.file', 0);
|
||||
|
||||
if(!empty($file)) {
|
||||
$item['image'] = $element->find('.file a', 0)->href;
|
||||
$item['imageThumb'] = $element->find('.file img', 0)->src;
|
||||
if(!isset($item['imageThumb']) and strpos($item['image'], '.swf') !== FALSE)
|
||||
if(!isset($item['imageThumb']) and strpos($item['image'], '.swf') !== false)
|
||||
$item['imageThumb'] = 'http://i.imgur.com/eO0cxf9.jpg';
|
||||
}
|
||||
|
||||
if(!empty($element->find('span.subject', 0)->innertext)) {
|
||||
$item['subject'] = $element->find('span.subject', 0)->innertext;
|
||||
}
|
||||
@@ -55,10 +60,15 @@ class FourchanBridge extends BridgeAbstract{
|
||||
$content = $element->find('.postMessage', 0)->innertext;
|
||||
$content = str_replace('href="#p', 'href="' . $this->getURI() . '#p', $content);
|
||||
$item['content'] = '<span id="' . $item['id'] . '">' . $content . '</span>';
|
||||
|
||||
if(isset($item['image'])) {
|
||||
$item['content'] = '<a href="'.$item['image'].'">'
|
||||
.'<img alt="'.$item['id'].'" src="'.$item['imageThumb'].'" />'
|
||||
.'</a><br>'
|
||||
$item['content'] = '<a href="'
|
||||
. $item['image']
|
||||
. '"><img alt="'
|
||||
. $item['id']
|
||||
. '" src="'
|
||||
. $item['imageThumb']
|
||||
. '" /></a><br>'
|
||||
.$item['content'];
|
||||
}
|
||||
$this->items[] = $item;
|
||||
|
@@ -88,12 +88,13 @@ class FuturaSciencesBridge extends FeedExpander {
|
||||
$item['uri'] = str_replace('#xtor=RSS-8', '', $item['uri']);
|
||||
$article = getSimpleHTMLDOMCached($item['uri'])
|
||||
or returnServerError('Could not request Futura-Sciences: ' . $item['uri']);
|
||||
$item['content'] = $this->ExtractArticleContent($article);
|
||||
$item['author'] = empty($this->ExtractAuthor($article)) ? $item['author'] : $this->ExtractAuthor($article);
|
||||
$item['content'] = $this->extractArticleContent($article);
|
||||
$author = $this->extractAuthor($article);
|
||||
$item['author'] = empty($author) ? $item['author'] : $author;
|
||||
return $item;
|
||||
}
|
||||
|
||||
function StripWithDelimiters($string, $start, $end) {
|
||||
private function stripWithDelimiters($string, $start, $end){
|
||||
while(strpos($string, $start) !== false) {
|
||||
$section_to_remove = substr($string, strpos($string, $start));
|
||||
$section_to_remove = substr($section_to_remove, 0, strpos($section_to_remove, $end) + strlen($end));
|
||||
@@ -101,7 +102,7 @@ class FuturaSciencesBridge extends FeedExpander {
|
||||
} return $string;
|
||||
}
|
||||
|
||||
function StripRecursiveHTMLSection($string, $tag_name, $tag_start) {
|
||||
private function stripRecursiveHTMLSection($string, $tag_name, $tag_start){
|
||||
$open_tag = '<' . $tag_name;
|
||||
$close_tag = '</' . $tag_name . '>';
|
||||
$close_tag_length = strlen($close_tag);
|
||||
@@ -125,13 +126,17 @@ class FuturaSciencesBridge extends FeedExpander {
|
||||
return $string;
|
||||
}
|
||||
|
||||
function ExtractArticleContent($article){
|
||||
$contents = $article->find('div.content', 0)->innertext;
|
||||
private function extractArticleContent($article){
|
||||
$contents = $article->find('section.article-text-classic', 0)->innertext;
|
||||
$headline = trim($article->find('p.description', 0)->plaintext);
|
||||
if(!empty($headline))
|
||||
$headline = '<p><b>' . $headline . '</b></p>';
|
||||
|
||||
foreach (array(
|
||||
'<div class="clear',
|
||||
'<div class="sharebar2',
|
||||
'<div class="diaporamafullscreen"',
|
||||
'<div class="module social-button',
|
||||
'<div style="margin-bottom:10px;" class="noprint"',
|
||||
'<div class="ficheprevnext',
|
||||
'<div class="bar noprint',
|
||||
@@ -140,24 +145,26 @@ class FuturaSciencesBridge extends FeedExpander {
|
||||
'<div class="noprint',
|
||||
'<div class="bg bglight border border-full noprint',
|
||||
'<div class="httplogbar-wrapper noprint',
|
||||
'<div id="forumcomments'
|
||||
'<div id="forumcomments',
|
||||
'<div ng-if="active"'
|
||||
) as $div_start) {
|
||||
$contents = $this->StripRecursiveHTMLSection($contents , 'div', $div_start);
|
||||
$contents = $this->stripRecursiveHTMLSection($contents, 'div', $div_start);
|
||||
}
|
||||
|
||||
$contents = $this->StripWithDelimiters($contents, '<hr ', '/>');
|
||||
$contents = $this->StripWithDelimiters($contents, '<p class="content-date', '</p>');
|
||||
$contents = $this->StripWithDelimiters($contents, '<h1 class="content-title', '</h1>');
|
||||
$contents = $this->StripWithDelimiters($contents, 'fs:definition="', '"');
|
||||
$contents = $this->StripWithDelimiters($contents, 'fs:xt:clicktype="', '"');
|
||||
$contents = $this->StripWithDelimiters($contents, 'fs:xt:clickname="', '"');
|
||||
$contents = $this->stripWithDelimiters($contents, '<hr ', '/>');
|
||||
$contents = $this->stripWithDelimiters($contents, '<p class="content-date', '</p>');
|
||||
$contents = $this->stripWithDelimiters($contents, '<h1 class="content-title', '</h1>');
|
||||
$contents = $this->stripWithDelimiters($contents, 'fs:definition="', '"');
|
||||
$contents = $this->stripWithDelimiters($contents, 'fs:xt:clicktype="', '"');
|
||||
$contents = $this->stripWithDelimiters($contents, 'fs:xt:clickname="', '"');
|
||||
$contents = $this->stripWithDelimiters($contents, '<script ', '</script>');
|
||||
|
||||
return $contents;
|
||||
return $headline . trim($contents);
|
||||
}
|
||||
|
||||
// Extracts the author from an article or element
|
||||
function ExtractAuthor($article){
|
||||
$article_author = $article->find('span.author', 0);
|
||||
private function extractAuthor($article){
|
||||
$article_author = $article->find('h3.epsilon', 0);
|
||||
if($article_author) {
|
||||
return trim(str_replace(', Futura-Sciences', '', $article_author->plaintext));
|
||||
}
|
||||
|
@@ -3,7 +3,7 @@ class GBAtempBridge extends BridgeAbstract {
|
||||
|
||||
const MAINTAINER = 'ORelio';
|
||||
const NAME = 'GBAtemp';
|
||||
const URI = 'http://gbatemp.net/';
|
||||
const URI = 'https://gbatemp.net/';
|
||||
const DESCRIPTION = 'GBAtemp is a user friendly underground video game community.';
|
||||
|
||||
const PARAMETERS = array( array(
|
||||
@@ -20,23 +20,27 @@ class GBAtempBridge extends BridgeAbstract {
|
||||
)
|
||||
));
|
||||
|
||||
private function ExtractFromDelimiters($string, $start, $end) {
|
||||
private 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;
|
||||
}
|
||||
|
||||
private function StripWithDelimiters($string, $start, $end) {
|
||||
return false;
|
||||
}
|
||||
|
||||
private function stripWithDelimiters($string, $start, $end){
|
||||
while(strpos($string, $start) !== false) {
|
||||
$section_to_remove = substr($string, strpos($string, $start));
|
||||
$section_to_remove = substr($section_to_remove, 0, strpos($section_to_remove, $end) + strlen($end));
|
||||
$string = str_replace($section_to_remove, '', $string);
|
||||
} return $string;
|
||||
}
|
||||
|
||||
private function build_item($uri, $title, $author, $timestamp, $content) {
|
||||
return $string;
|
||||
}
|
||||
|
||||
private function buildItem($uri, $title, $author, $timestamp, $content){
|
||||
$item = array();
|
||||
$item['uri'] = $uri;
|
||||
$item['title'] = $title;
|
||||
@@ -46,21 +50,21 @@ class GBAtempBridge extends BridgeAbstract {
|
||||
return $item;
|
||||
}
|
||||
|
||||
private function cleanup_post_content($content, $site_url) {
|
||||
private function cleanupPostContent($content, $site_url){
|
||||
$content = str_replace(':arrow:', '➤', $content);
|
||||
$content = str_replace('href="attachments/', 'href="'.$site_url.'attachments/', $content);
|
||||
$content = $this->StripWithDelimiters($content, '<script', '</script>');
|
||||
$content = $this->stripWithDelimiters($content, '<script', '</script>');
|
||||
return $content;
|
||||
}
|
||||
|
||||
private function fetch_post_content($uri, $site_url) {
|
||||
private function fetchPostContent($uri, $site_url){
|
||||
$html = getSimpleHTMLDOM($uri);
|
||||
if(!$html) {
|
||||
return 'Could not request GBAtemp ' . $uri;
|
||||
}
|
||||
|
||||
$content = $html->find('div.messageContent', 0)->innertext;
|
||||
return $this->cleanup_post_content($content, $site_url);
|
||||
return $this->cleanupPostContent($content, $site_url);
|
||||
}
|
||||
|
||||
public function collectData(){
|
||||
@@ -72,53 +76,82 @@ class GBAtempBridge extends BridgeAbstract {
|
||||
case 'N':
|
||||
foreach($html->find('li[class=news_item full]') as $newsItem) {
|
||||
$url = self::URI . $newsItem->find('a', 0)->href;
|
||||
$time = intval($this->ExtractFromDelimiters($newsItem->find('abbr.DateTime', 0)->outertext, 'data-time="', '"'));
|
||||
$time = intval(
|
||||
$this->extractFromDelimiters(
|
||||
$newsItem->find('abbr.DateTime', 0)->outertext,
|
||||
'data-time="',
|
||||
'"'
|
||||
)
|
||||
);
|
||||
$author = $newsItem->find('a.username', 0)->plaintext;
|
||||
$title = $newsItem->find('a', 1)->plaintext;
|
||||
$content = $this->fetch_post_content($url, self::URI);
|
||||
$this->items[] = $this->build_item($url, $title, $author, $time, $content);
|
||||
$content = $this->fetchPostContent($url, self::URI);
|
||||
$this->items[] = $this->buildItem($url, $title, $author, $time, $content);
|
||||
}
|
||||
case 'R':
|
||||
foreach($html->find('li.portal_review') as $reviewItem) {
|
||||
$url = self::URI . $reviewItem->find('a', 0)->href;
|
||||
$title = $reviewItem->find('span.review_title', 0)->plaintext;
|
||||
$content = getSimpleHTMLDOM($url) or returnServerError('Could not request GBAtemp: '.$uri);
|
||||
$content = getSimpleHTMLDOM($url)
|
||||
or returnServerError('Could not request GBAtemp: ' . $uri);
|
||||
$author = $content->find('a.username', 0)->plaintext;
|
||||
$time = intval($this->ExtractFromDelimiters($content->find('abbr.DateTime', 0)->outertext, 'data-time="', '"'));
|
||||
$time = intval(
|
||||
$this->extractFromDelimiters(
|
||||
$content->find('abbr.DateTime', 0)->outertext,
|
||||
'data-time="',
|
||||
'"'
|
||||
)
|
||||
);
|
||||
$intro = '<p><b>' . ($content->find('div#review_intro', 0)->plaintext) . '</b></p>';
|
||||
$review = $content->find('div#review_main', 0)->innertext;
|
||||
$subheader = '<p><b>' . $content->find('div.review_subheader', 0)->plaintext . '</b></p>';
|
||||
$procons = $content->find('table.review_procons', 0)->outertext;
|
||||
$scores = $content->find('table.reviewscores', 0)->outertext;
|
||||
$content = $this->cleanup_post_content($intro.$review.$subheader.$procons.$scores, self::URI);
|
||||
$this->items[] = $this->build_item($url, $title, $author, $time, $content);
|
||||
$content = $this->cleanupPostContent($intro . $review . $subheader . $procons . $scores, self::URI);
|
||||
$this->items[] = $this->buildItem($url, $title, $author, $time, $content);
|
||||
}
|
||||
case 'T':
|
||||
foreach($html->find('li.portal-tutorial') as $tutorialItem) {
|
||||
$url = self::URI . $tutorialItem->find('a', 0)->href;
|
||||
$title = $tutorialItem->find('a', 0)->plaintext;
|
||||
$time = intval($this->ExtractFromDelimiters($tutorialItem->find('abbr.DateTime', 0)->outertext, 'data-time="', '"'));
|
||||
$time = intval(
|
||||
$this->extractFromDelimiters(
|
||||
$tutorialItem->find('abbr.DateTime', 0)->outertext,
|
||||
'data-time="',
|
||||
'"'
|
||||
)
|
||||
);
|
||||
$author = $tutorialItem->find('a.username', 0)->plaintext;
|
||||
$content = $this->fetch_post_content($url, self::URI);
|
||||
$this->items[] = $this->build_item($url, $title, $author, $time, $content);
|
||||
$content = $this->fetchPostContent($url, self::URI);
|
||||
$this->items[] = $this->buildItem($url, $title, $author, $time, $content);
|
||||
}
|
||||
case 'F':
|
||||
foreach($html->find('li.rc_item') as $postItem) {
|
||||
$url = self::URI . $postItem->find('a', 1)->href;
|
||||
$title = $postItem->find('a', 1)->plaintext;
|
||||
$time = intval($this->ExtractFromDelimiters($postItem->find('abbr.DateTime', 0)->outertext, 'data-time="', '"'));
|
||||
$time = intval(
|
||||
$this->extractFromDelimiters(
|
||||
$postItem->find('abbr.DateTime', 0)->outertext,
|
||||
'data-time="',
|
||||
'"'
|
||||
)
|
||||
);
|
||||
$author = $postItem->find('a.username', 0)->plaintext;
|
||||
$content = $this->fetch_post_content($url, self::URI);
|
||||
$this->items[] = $this->build_item($url, $title, $author, $time, $content);
|
||||
$content = $this->fetchPostContent($url, self::URI);
|
||||
$this->items[] = $this->buildItem($url, $title, $author, $time, $content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getName() {
|
||||
if(!is_null($this->getInput('type'))) {
|
||||
$type = array_search(
|
||||
$this->getInput('type'),
|
||||
self::PARAMETERS[$this->queriedContext]['type']['values']
|
||||
);
|
||||
return 'GBAtemp ' . $type . ' Bridge';
|
||||
}
|
||||
|
||||
return parent::getName();
|
||||
}
|
||||
}
|
||||
|
@@ -3,19 +3,33 @@ require_once('DanbooruBridge.php');
|
||||
|
||||
class GelbooruBridge extends DanbooruBridge {
|
||||
|
||||
const MAINTAINER = "mitsukarenai";
|
||||
const NAME = "Gelbooru";
|
||||
const URI = "http://gelbooru.com/";
|
||||
const DESCRIPTION = "Returns images from given page";
|
||||
const MAINTAINER = 'mitsukarenai';
|
||||
const NAME = 'Gelbooru';
|
||||
const URI = 'http://gelbooru.com/';
|
||||
const DESCRIPTION = 'Returns images from given page';
|
||||
|
||||
const PATHTODATA = '.thumb';
|
||||
const IDATTRIBUTE = 'id';
|
||||
const TAGATTRIBUTE = 'title';
|
||||
|
||||
const PIDBYPAGE = 63;
|
||||
|
||||
protected function getFullURI(){
|
||||
return $this->getURI().'index.php?page=post&s=list&'
|
||||
.'&pid='.($this->getInput('p')?($this->getInput('p') -1)*static::PIDBYPAGE:'')
|
||||
return $this->getURI()
|
||||
. 'index.php?page=post&s=list&pid='
|
||||
. ($this->getInput('p') ? ($this->getInput('p') - 1) * static::PIDBYPAGE : '')
|
||||
. '&tags=' . urlencode($this->getInput('t'));
|
||||
}
|
||||
|
||||
protected function getTags($element){
|
||||
$tags = parent::getTags($element);
|
||||
$tags = explode(' ', $tags);
|
||||
|
||||
// Remove statistics from the tags list (identified by colon)
|
||||
foreach($tags as $key => $tag) {
|
||||
if(strpos($tag, ':') !== false) unset($tags[$key]);
|
||||
}
|
||||
|
||||
return implode(' ', $tags);
|
||||
}
|
||||
}
|
||||
|
@@ -3,11 +3,11 @@ define('GIPHY_LIMIT', 10);
|
||||
|
||||
class GiphyBridge extends BridgeAbstract {
|
||||
|
||||
const MAINTAINER = "kraoc";
|
||||
const NAME = "Giphy Bridge";
|
||||
const URI = "http://giphy.com/";
|
||||
const MAINTAINER = 'kraoc';
|
||||
const NAME = 'Giphy Bridge';
|
||||
const URI = 'http://giphy.com/';
|
||||
const CACHE_TIMEOUT = 300; //5min
|
||||
const DESCRIPTION = "Bridge for giphy.com";
|
||||
const DESCRIPTION = 'Bridge for giphy.com';
|
||||
|
||||
const PARAMETERS = array( array(
|
||||
's' => array(
|
||||
@@ -58,10 +58,15 @@ class GiphyBridge extends BridgeAbstract{
|
||||
$title = $item['id'];
|
||||
}
|
||||
$item['title'] = trim($title);
|
||||
$item['content'] =
|
||||
'<a href="'.$item['uri'].'">'
|
||||
.'<img src="'.$img->getAttribute('src').'" width="'.$img->getAttribute('data-original-width').'" height="'.$img->getAttribute('data-original-height').'" />'
|
||||
.'</a>';
|
||||
$item['content'] = '<a href="'
|
||||
. $item['uri']
|
||||
. '"><img src="'
|
||||
. $img->getAttribute('src')
|
||||
. '" width="'
|
||||
. $img->getAttribute('data-original-width')
|
||||
. '" height="'
|
||||
. $img->getAttribute('data-original-height')
|
||||
. '" /></a>';
|
||||
|
||||
$this->items[] = $item;
|
||||
$limit++;
|
||||
|
@@ -18,7 +18,6 @@ class GithubIssueBridge extends BridgeAbstract{
|
||||
'required' => true
|
||||
)
|
||||
),
|
||||
|
||||
'Project Issues' => array(
|
||||
'c' => array(
|
||||
'name' => 'Show Issues Comments',
|
||||
@@ -48,11 +47,13 @@ class GithubIssueBridge extends BridgeAbstract{
|
||||
case 'Issue comments':
|
||||
$name = static::NAME . ' ' . $name . ' #' . $this->getInput('i');
|
||||
break;
|
||||
default: return parent::getName();
|
||||
}
|
||||
return $name;
|
||||
}
|
||||
|
||||
public function getURI(){
|
||||
if(!is_null($this->getInput('u')) && !is_null($this->getInput('p'))) {
|
||||
$uri = static::URI . $this->getInput('u') . '/' . $this->getInput('p') . '/issues';
|
||||
if($this->queriedContext === 'Issue comments') {
|
||||
$uri .= '/' . $this->getInput('i');
|
||||
@@ -62,6 +63,9 @@ class GithubIssueBridge extends BridgeAbstract{
|
||||
return $uri;
|
||||
}
|
||||
|
||||
return parent::getURI();
|
||||
}
|
||||
|
||||
protected function extractIssueComment($issueNbr, $title, $comment){
|
||||
$class = $comment->getAttribute('class');
|
||||
$classes = explode(' ', $class);
|
||||
@@ -75,8 +79,7 @@ class GithubIssueBridge extends BridgeAbstract{
|
||||
$author = $comment->find('.author', 0)->plaintext;
|
||||
}
|
||||
|
||||
$uri=static::URI.$this->getInput('u').'/'.$this->getInput('p').'/issues/'
|
||||
.$issueNbr;
|
||||
$uri = static::URI . $this->getInput('u') . '/' . $this->getInput('p') . '/issues/' . $issueNbr;
|
||||
|
||||
$comment = $comment->firstChild();
|
||||
if(!$event) {
|
||||
@@ -122,9 +125,8 @@ class GithubIssueBridge extends BridgeAbstract{
|
||||
$comments = $issue->find('.js-discussion', 0);
|
||||
foreach($comments->children() as $comment) {
|
||||
$classes = explode(' ', $comment->getAttribute('class'));
|
||||
if(in_array('discussion-item',$classes) ||
|
||||
in_array('timeline-comment-wrapper',$classes)
|
||||
){
|
||||
if(in_array('discussion-item', $classes)
|
||||
|| in_array('timeline-comment-wrapper', $classes)) {
|
||||
$item = $this->extractIssueComment($issueNbr, $title, $comment);
|
||||
if(array_keys($item) !== range(0, count($item) - 1)) {
|
||||
$item = array($item);
|
||||
|
50
bridges/GithubSearchBridge.php
Normal file
50
bridges/GithubSearchBridge.php
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
class GithubSearchBridge extends BridgeAbstract {
|
||||
|
||||
const MAINTAINER = 'corenting';
|
||||
const NAME = 'Github Repositories Search';
|
||||
const URI = 'https://github.com/';
|
||||
const CACHE_TIMEOUT = 600; // 10min
|
||||
const DESCRIPTION = 'Returns a specified repositories search (sorted by recently updated)';
|
||||
const PARAMETERS = array( array(
|
||||
's' => array(
|
||||
'type' => 'text',
|
||||
'name' => 'Search query'
|
||||
)
|
||||
));
|
||||
|
||||
public function collectData(){
|
||||
$params = array('utf8' => '✓',
|
||||
'q' => urlencode($this->getInput('s')),
|
||||
's' => 'updated',
|
||||
'o' => 'desc',
|
||||
'type' => 'Repositories');
|
||||
$url = self::URI . 'search?' . http_build_query($params);
|
||||
|
||||
$html = getSimpleHTMLDOM($url)
|
||||
or returnServerError('Error while downloading the website content');
|
||||
|
||||
foreach($html->find('div.repo-list-item') as $element) {
|
||||
$item = array();
|
||||
|
||||
$uri = $element->find('h3 a', 0)->href;
|
||||
$uri = substr(self::URI, 0, -1) . $uri;
|
||||
$item['uri'] = $uri;
|
||||
|
||||
$title = $element->find('h3', 0)->plaintext;
|
||||
$item['title'] = $title;
|
||||
|
||||
if (count($element->find('p')) == 2) {
|
||||
$content = $element->find('p', 0)->innertext;
|
||||
} else{
|
||||
$content = '';
|
||||
}
|
||||
$item['content'] = $content;
|
||||
|
||||
$date = $element->find('relative-time', 0)->datetime;
|
||||
$item['timestamp'] = strtotime($date);
|
||||
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,11 +1,11 @@
|
||||
<?php
|
||||
class GizmodoBridge extends FeedExpander {
|
||||
|
||||
const MAINTAINER = "polopollo";
|
||||
const NAME = "Gizmodo";
|
||||
const URI = "http://gizmodo.com/";
|
||||
const MAINTAINER = 'polopollo';
|
||||
const NAME = 'Gizmodo';
|
||||
const URI = 'http://gizmodo.com/';
|
||||
const CACHE_TIMEOUT = 1800; // 30min
|
||||
const DESCRIPTION = "Returns the newest posts from Gizmodo (full text).";
|
||||
const DESCRIPTION = 'Returns the newest posts from Gizmodo (full text).';
|
||||
|
||||
protected function parseItem($item){
|
||||
$item = parent::parseItem($item);
|
||||
@@ -16,7 +16,11 @@ class GizmodoBridge extends FeedExpander {
|
||||
} else {
|
||||
$text = $articleHTMLContent->find('div.entry-content', 0)->innertext;
|
||||
foreach($articleHTMLContent->find('pagespeed_iframe') as $element) {
|
||||
$text .= '<p>link to a iframe (could be a video): <a href="'.$element->src.'">'.$element->src.'</a></p><br>';
|
||||
$text .= '<p>link to a iframe (could be a video): <a href="'
|
||||
. $element->src
|
||||
. '">'
|
||||
. $element->src
|
||||
. '</a></p><br>';
|
||||
}
|
||||
|
||||
$text = strip_tags($text, '<p><b><a><blockquote><img><em>');
|
||||
|
59
bridges/GoComicsBridge.php
Normal file
59
bridges/GoComicsBridge.php
Normal file
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
class GoComicsBridge extends BridgeAbstract {
|
||||
|
||||
const MAINTAINER = 'sky';
|
||||
const NAME = 'GoComics Unofficial RSS';
|
||||
const URI = 'http://www.gocomics.com/';
|
||||
const CACHE_TIMEOUT = 21600; // 6h
|
||||
const DESCRIPTION = 'The Unofficial GoComics RSS';
|
||||
const PARAMETERS = array( array(
|
||||
'comicname' => array(
|
||||
'name' => 'comicname',
|
||||
'type' => 'text',
|
||||
'required' => true
|
||||
)
|
||||
));
|
||||
|
||||
public function collectData(){
|
||||
$html = getSimpleHTMLDOM($this->getURI())
|
||||
or returnServerError('Could not request GoComics: ' . $this->getURI());
|
||||
|
||||
foreach($html->find('div.comic__container') as $element) {
|
||||
|
||||
$img = $element->find('.item-comic-image img', 0);
|
||||
$link = $element->find('a.js-item-comic-link', 0);
|
||||
$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['id'] = $url;
|
||||
$item['uri'] = $url;
|
||||
$item['title'] = $title;
|
||||
$item['author'] = preg_replace('/by /', '', $element->find('a.link-blended small', 0)->plaintext);
|
||||
$item['timestamp'] = $date;
|
||||
$item['content'] = '<img src="' . $comic . '" alt="' . $title . '" />';
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
public function getURI(){
|
||||
if(!is_null($this->getInput('comicname'))) {
|
||||
return self::URI . urlencode($this->getInput('comicname'));
|
||||
}
|
||||
|
||||
return parent::getURI();
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
if(!is_null($this->getInput('comicname'))) {
|
||||
return $this->getInput('comicname') . ' - GoComics';
|
||||
}
|
||||
|
||||
return parent::getName();
|
||||
}
|
||||
}
|
@@ -1,14 +1,14 @@
|
||||
<?php
|
||||
class GooglePlusPostBridge extends BridgeAbstract
|
||||
{
|
||||
class GooglePlusPostBridge extends BridgeAbstract{
|
||||
|
||||
protected $_title;
|
||||
protected $_url;
|
||||
|
||||
const MAINTAINER = "Grummfy";
|
||||
const NAME = "Google Plus Post Bridge";
|
||||
const URI = "https://plus.google.com/";
|
||||
const MAINTAINER = 'Grummfy';
|
||||
const NAME = 'Google Plus Post Bridge';
|
||||
const URI = 'https://plus.google.com/';
|
||||
const CACHE_TIMEOUT = 600; //10min
|
||||
const DESCRIPTION = "Returns user public post (without API).";
|
||||
const DESCRIPTION = 'Returns user public post (without API).';
|
||||
|
||||
const PARAMETERS = array( array(
|
||||
'username' => array(
|
||||
@@ -17,97 +17,95 @@ class GooglePlusPostBridge extends BridgeAbstract
|
||||
)
|
||||
));
|
||||
|
||||
public function collectData()
|
||||
{
|
||||
public function collectData(){
|
||||
$username = $this->getInput('username');
|
||||
|
||||
// Usernames start with a + if it's not an ID
|
||||
if(!is_numeric($username) && substr($username, 0, 1) !== '+') {
|
||||
$username = '+' . $username;
|
||||
}
|
||||
|
||||
// get content parsed
|
||||
// $html = getSimpleHTMLDOM(__DIR__ . '/../posts2.html'
|
||||
$html = getSimpleHTMLDOM(self::URI . urlencode($this->getInput('username')) . '/posts'
|
||||
// force language
|
||||
, false, stream_context_create(array('http'=> array(
|
||||
'header' => 'Accept-Language: fr,fr-be,fr-fr;q=0.8,en;q=0.4,en-us;q=0.2;*' . "\r\n"
|
||||
)))
|
||||
) OR returnServerError('No results for this query.');
|
||||
$html = getSimpleHTMLDOMCached(self::URI . urlencode($username) . '/posts')
|
||||
or returnServerError('No results for this query.');
|
||||
|
||||
// get title, url, ... there is a lot of intresting stuff in meta
|
||||
$this->_title = $html->find('meta[property]', 0)->getAttribute('content');
|
||||
$this->_url = $html->find('meta[itemprop=url]', 0)->getAttribute('content');
|
||||
$this->_title = $html->find('meta[property=og:title]', 0)->getAttribute('content');
|
||||
$this->_url = $html->find('meta[property=og:url]', 0)->getAttribute('content');
|
||||
|
||||
// foreach ($html->find('meta') as $e)
|
||||
// {
|
||||
// $item = array();
|
||||
// $item['content'] = var_export($e->attr, true);
|
||||
// $this->items[] = $item;
|
||||
// }
|
||||
|
||||
// div[jsmodel=XNmfOc]
|
||||
foreach($html->find('div.yt') as $post)
|
||||
{
|
||||
// I don't even know where to start with this discusting html...
|
||||
foreach($html->find('div[jsname=WsjYwc]') as $post) {
|
||||
$item = array();
|
||||
// $item['content'] = $post->find('div.Al', 0)->innertext;
|
||||
$item['username'] = $item['fullname'] = $post->find('header.lea h3 a', 0)->innertext;
|
||||
$item['id'] = $post->getAttribute('id');
|
||||
// $item['title'] = $item['fullname'] = $post->find('header.lea', 0)->plaintext;
|
||||
$item['avatar'] = $post->find('div.ys img', 0)->src;
|
||||
// var_dump((($post->find('a.o-U-s', 0)->getAllAttributes())));
|
||||
$item['uri'] = self::URI . $post->find('a.o-U-s', 0)->href;
|
||||
$item['timestamp'] = strtotime($post->find('a.o-U-s', 0)->plaintext);
|
||||
$this->items[] = $item;
|
||||
|
||||
$item['author'] = $item['fullname'] = $post->find('div div div div a', 0)->innertext;
|
||||
$item['id'] = $post->find('div div div', 0)->getAttribute('id');
|
||||
$item['avatar'] = $post->find('div img', 0)->src;
|
||||
$item['uri'] = self::URI . $post->find('div div div a', 1)->href;
|
||||
|
||||
$timestamp = $post->find('a.qXj2He span', 0);
|
||||
|
||||
if($timestamp) {
|
||||
$item['timestamp'] = strtotime('+' . preg_replace(
|
||||
'/[^0-9A-Za-z]/',
|
||||
'',
|
||||
$timestamp->getAttribute('aria-label')));
|
||||
}
|
||||
|
||||
// hashtag to treat : https://plus.google.com/explore/tag
|
||||
$hashtags = array();
|
||||
foreach($post->find('a.d-s') as $hashtag)
|
||||
{
|
||||
$hashtags[ trim($hashtag->plaintext) ] = self::URI . $hashtag->href;
|
||||
}
|
||||
// $hashtags = array();
|
||||
// foreach($post->find('a.d-s') as $hashtag){
|
||||
// $hashtags[trim($hashtag->plaintext)] = self::URI . $hashtag->href;
|
||||
// }
|
||||
|
||||
$item['content'] = '';
|
||||
|
||||
// avatar display
|
||||
$item['content'] .= '<div style="float:left; margin: 0 0.5em 0.5em 0;"><a href="' . self::URI . urlencode($this->getInput('username'));
|
||||
$item['content'] .= '"><img align="top" alt="avatar" src="' . $item['avatar'].'" />' . $item['username'] . '</a></div>';
|
||||
$item['content'] .= '<div style="float:left; margin: 0 0.5em 0.5em 0;"><a href="'
|
||||
. self::URI
|
||||
. urlencode($this->getInput('username'));
|
||||
|
||||
$content = $post->find('div.Al', 0);
|
||||
$item['content'] .= '"><img align="top" alt="'
|
||||
. $item['author']
|
||||
. '" src="'
|
||||
. $item['avatar']
|
||||
. '" /></a></div>';
|
||||
|
||||
// alter link
|
||||
// $content = $content->innertext;
|
||||
// $content = str_replace('href="./', 'href="' . self::URI, $content);
|
||||
// $content = str_replace('href="photos', 'href="' . self::URI . 'photos', $content);
|
||||
// XXX ugly but I don't have any idea how to do a better stuff, str_replace on link doesn't work as expected and ask too many checks
|
||||
foreach($content->find('a') as $link)
|
||||
{
|
||||
$content = $post->find('div[jsname=EjRJtf]', 0);
|
||||
// extract plaintext
|
||||
$item['content_simple'] = $content->plaintext;
|
||||
$item['title'] = substr($item['content_simple'], 0, 72) . '...';
|
||||
|
||||
// XXX ugly but I don't have any idea how to do a better stuff,
|
||||
// str_replace on link doesn't work as expected and ask too many checks
|
||||
foreach($content->find('a') as $link) {
|
||||
$hasHttp = strpos($link->href, 'http');
|
||||
$hasDoubleSlash = strpos($link->href, '//');
|
||||
|
||||
if((!$hasHttp && !$hasDoubleSlash)
|
||||
|| (false !== $hasHttp && strpos($link->href, 'http') != 0)
|
||||
|| (false === $hasHttp && false !== $hasDoubleSlash && $hasDoubleSlash != 0))
|
||||
{
|
||||
|| (false === $hasHttp && false !== $hasDoubleSlash && $hasDoubleSlash != 0)) {
|
||||
// skipp bad link, for some hashtag or other stuff
|
||||
if (strpos($link->href, '/') == 0)
|
||||
{
|
||||
if(strpos($link->href, '/') == 0) {
|
||||
$link->href = substr($link->href, 1);
|
||||
}
|
||||
|
||||
$link->href = self::URI . $link->href;
|
||||
}
|
||||
}
|
||||
$content = $content->innertext;
|
||||
|
||||
$item['content'] .= '<div style="margin-top: -1.5em">' . $content . '</div>';
|
||||
$item['content'] = trim(strip_tags($item['content'], '<a><p><div><img>'));
|
||||
|
||||
// extract plaintext
|
||||
$item['content_simple'] = $post->find('div.Al', 0)->plaintext;
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
// $html->save(__DIR__ . '/../posts2.html');
|
||||
}
|
||||
|
||||
public function getName()
|
||||
{
|
||||
public function getName(){
|
||||
return $this->_title ?: 'Google Plus Post Bridge';
|
||||
}
|
||||
|
||||
public function getURI()
|
||||
{
|
||||
return $this->_url ?: self::URI;
|
||||
public function getURI(){
|
||||
return $this->_url ?: parent::getURI();
|
||||
}
|
||||
}
|
||||
|
@@ -9,11 +9,11 @@
|
||||
*/
|
||||
class GoogleSearchBridge extends BridgeAbstract {
|
||||
|
||||
const MAINTAINER = "sebsauvage";
|
||||
const NAME = "Google search";
|
||||
const URI = "https://www.google.com/";
|
||||
const MAINTAINER = 'sebsauvage';
|
||||
const NAME = 'Google search';
|
||||
const URI = 'https://www.google.com/';
|
||||
const CACHE_TIMEOUT = 1800; // 30min
|
||||
const DESCRIPTION = "Returns most recent results from Google search.";
|
||||
const DESCRIPTION = 'Returns most recent results from Google search.';
|
||||
|
||||
const PARAMETERS = array(array(
|
||||
'q' => array(
|
||||
@@ -22,33 +22,43 @@ class GoogleSearchBridge extends BridgeAbstract{
|
||||
)
|
||||
));
|
||||
|
||||
|
||||
public function collectData(){
|
||||
$html = '';
|
||||
|
||||
$html = getSimpleHTMLDOM(self::URI
|
||||
.'search?q=' . urlencode($this->getInput('q'))
|
||||
. 'search?q='
|
||||
. urlencode($this->getInput('q'))
|
||||
.'&num=100&complete=0&tbs=qdr:y,sbd:1')
|
||||
or returnServerError('No results for this query.');
|
||||
|
||||
$emIsRes = $html->find('div[id=ires]', 0);
|
||||
|
||||
if(!is_null($emIsRes)) {
|
||||
foreach($emIsRes->find('li[class=g]') as $element) {
|
||||
foreach($emIsRes->find('div[class=g]') as $element) {
|
||||
|
||||
$item = array();
|
||||
|
||||
// Extract direct URL from google href (eg. /url?q=...)
|
||||
$t = $element->find('a[href]', 0)->href;
|
||||
$item['uri'] = '' . $t;
|
||||
parse_str(parse_url($t, PHP_URL_QUERY), $parameters);
|
||||
if (isset($parameters['q'])) { $item['uri'] = $parameters['q']; }
|
||||
if(isset($parameters['q'])) {
|
||||
$item['uri'] = $parameters['q'];
|
||||
}
|
||||
|
||||
$item['title'] = $element->find('h3', 0)->plaintext;
|
||||
$item['content'] = $element->find('span[class=st]', 0)->plaintext;
|
||||
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
if(!is_null($this->getInput('q'))) {
|
||||
return $this->getInput('q') . ' - Google search';
|
||||
}
|
||||
|
||||
return parent::getName();
|
||||
}
|
||||
}
|
||||
|
@@ -1,17 +1,19 @@
|
||||
<?php
|
||||
class HDWallpapersBridge extends BridgeAbstract {
|
||||
const MAINTAINER = "nel50n";
|
||||
const NAME = "HD Wallpapers Bridge";
|
||||
const URI = "http://www.hdwallpapers.in/";
|
||||
const MAINTAINER = 'nel50n';
|
||||
const NAME = 'HD Wallpapers Bridge';
|
||||
const URI = 'http://www.hdwallpapers.in/';
|
||||
const CACHE_TIMEOUT = 43200; //12h
|
||||
const DESCRIPTION = "Returns the latests wallpapers from HDWallpapers";
|
||||
const DESCRIPTION = 'Returns the latests wallpapers from HDWallpapers';
|
||||
|
||||
const PARAMETERS = array( array(
|
||||
'c' => array(
|
||||
'name' => 'category',
|
||||
'defaultValue' => 'latest_wallpapers'
|
||||
),
|
||||
'm'=>array('name'=>'max number of wallpapers'),
|
||||
'm' => array(
|
||||
'name' => 'max number of wallpapers'
|
||||
),
|
||||
'r' => array(
|
||||
'name' => 'resolution',
|
||||
'defaultValue' => '1920x1200',
|
||||
@@ -31,7 +33,8 @@ class HDWallpapersBridge extends BridgeAbstract {
|
||||
|
||||
for($page = 1; $page <= $lastpage; $page++) {
|
||||
$link = self::URI . '/' . $category . '/page/' . $page;
|
||||
$html = getSimpleHTMLDOM($link) or returnServerError('No results for this query.');
|
||||
$html = getSimpleHTMLDOM($link)
|
||||
or returnServerError('No results for this query.');
|
||||
|
||||
if($page === 1) {
|
||||
preg_match('/page\/(\d+)$/', $html->find('.pagination a', -2)->href, $matches);
|
||||
@@ -43,10 +46,20 @@ class HDWallpapersBridge extends BridgeAbstract {
|
||||
|
||||
$item = array();
|
||||
// http://www.hdwallpapers.in/download/yosemite_reflections-1680x1050.jpg
|
||||
$item['uri'] = self::URI.'/download'.str_replace('wallpapers.html', $this->getInput('r').'.jpg', $element->href);
|
||||
$item['uri'] = self::URI
|
||||
. '/download'
|
||||
. str_replace('wallpapers.html', $this->getInput('r') . '.jpg', $element->href);
|
||||
|
||||
$item['timestamp'] = time();
|
||||
$item['title'] = $element->find('p', 0)->text();
|
||||
$item['content'] = $item['title'].'<br><a href="'.$item['uri'].'"><img src="'.self::URI.$thumbnail->src.'" /></a>';
|
||||
$item['content'] = $item['title']
|
||||
. '<br><a href="'
|
||||
. $item['uri']
|
||||
. '"><img src="'
|
||||
. self::URI
|
||||
. $thumbnail->src
|
||||
. '" /></a>';
|
||||
|
||||
$this->items[] = $item;
|
||||
|
||||
$num++;
|
||||
@@ -57,6 +70,14 @@ class HDWallpapersBridge extends BridgeAbstract {
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return 'HDWallpapers - '.str_replace(['__', '_'], [' & ', ' '], $this->getInput('c')).' ['.$this->getInput('r').']';
|
||||
if(!is_null($this->getInput('c')) && !is_null($this->getInput('r'))) {
|
||||
return 'HDWallpapers - '
|
||||
. str_replace(['__', '_'], [' & ', ' '], $this->getInput('c'))
|
||||
. ' ['
|
||||
. $this->getInput('r')
|
||||
. ']';
|
||||
}
|
||||
|
||||
return parent::getName();
|
||||
}
|
||||
}
|
||||
|
@@ -1,22 +1,36 @@
|
||||
<?php
|
||||
class HentaiHavenBridge extends BridgeAbstract {
|
||||
|
||||
const MAINTAINER = "albirew";
|
||||
const NAME = "Hentai Haven";
|
||||
const URI = "http://hentaihaven.org/";
|
||||
const MAINTAINER = 'albirew';
|
||||
const NAME = 'Hentai Haven';
|
||||
const URI = 'http://hentaihaven.org/';
|
||||
const CACHE_TIMEOUT = 21600; // 6h
|
||||
const DESCRIPTION = "Returns releases from Hentai Haven";
|
||||
const DESCRIPTION = 'Returns releases from Hentai Haven';
|
||||
|
||||
public function collectData(){
|
||||
$html = getSimpleHTMLDOM(self::URI)
|
||||
or returnServerError('Could not request Hentai Haven.');
|
||||
|
||||
foreach($html->find('div.zoe-grid') as $element) {
|
||||
$item = array();
|
||||
$item['uri'] = $element->find('div.brick-content h3 a', 0)->href;
|
||||
$thumbnailUri = $element->find('a.thumbnail-image img', 0)->getAttribute('data-src');
|
||||
$item['title'] = mb_convert_encoding(trim($element->find('div.brick-content h3 a', 0)->innertext), 'UTF-8', 'HTML-ENTITIES');
|
||||
$item['title'] = mb_convert_encoding(
|
||||
trim($element->find('div.brick-content h3 a', 0)->innertext),
|
||||
'UTF-8',
|
||||
'HTML-ENTITIES'
|
||||
);
|
||||
|
||||
$item['tags'] = $element->find('div.oFlyout_bg div.oFlyout div.flyoutContent span.tags', 0)->plaintext;
|
||||
$item['content'] = 'Tags: ' . $item['tags'].'<br><br><a href="' . $item['uri'] . '"><img width="300" height="169" src="' . $thumbnailUri . '" /></a><br>' . $element->find('div.oFlyout_bg div.oFlyout div.flyoutContent p.description', 0)->innertext;
|
||||
$item['content'] = 'Tags: '
|
||||
. $item['tags']
|
||||
. '<br><br><a href="'
|
||||
. $item['uri']
|
||||
. '"><img width="300" height="169" src="'
|
||||
. $thumbnailUri
|
||||
. '" /></a><br>'
|
||||
. $element->find('div.oFlyout_bg div.oFlyout div.flyoutContent p.description', 0)->innertext;
|
||||
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
|
310
bridges/IPBBridge.php
Normal file
310
bridges/IPBBridge.php
Normal file
@@ -0,0 +1,310 @@
|
||||
<?php
|
||||
class IPBBridge extends FeedExpander {
|
||||
|
||||
const NAME = 'IPB Bridge';
|
||||
const URI = 'https://www.invisionpower.com';
|
||||
const DESCRIPTION = 'Returns feeds for forums powered by IPB';
|
||||
const MAINTAINER = 'logmanoriginal';
|
||||
const PARAMETERS = array(
|
||||
array(
|
||||
'uri' => array(
|
||||
'name' => 'URI',
|
||||
'type' => 'text',
|
||||
'required' => true,
|
||||
'title' => 'Insert forum, subforum or topic URI',
|
||||
'exampleValue' => 'https://invisioncommunity.com/forums/forum/499-feedback-and-ideas/'
|
||||
),
|
||||
'limit' => array(
|
||||
'name' => 'Limit',
|
||||
'type' => 'number',
|
||||
'required' => false,
|
||||
'title' => 'Specifies the number of items to return on each request (-1: all)',
|
||||
'defaultValue' => 10
|
||||
)
|
||||
)
|
||||
);
|
||||
const CACHE_TIMEOUT = 3600;
|
||||
|
||||
// Constants for internal use
|
||||
const FORUM_TYPE_LIST_FILTER = '.cForumTopicTable';
|
||||
const FORUM_TYPE_TABLE_FILTER = '#forum_table';
|
||||
|
||||
const TOPIC_TYPE_ARTICLE = 'article';
|
||||
const TOPIC_TYPE_DIV = 'div.post_block';
|
||||
|
||||
public function getURI(){
|
||||
return $this->getInput('uri') ?: parent::getURI();
|
||||
}
|
||||
|
||||
public function collectData(){
|
||||
// The URI cannot be the mainpage (or anything related)
|
||||
switch(parse_url($this->getInput('uri'), PHP_URL_PATH)) {
|
||||
case null:
|
||||
case '/index.php':
|
||||
returnClientError('Provided URI is invalid!');
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Sanitize the URI (because else it won't work)
|
||||
$uri = rtrim($this->getInput('uri'), '/'); // No trailing slashes!
|
||||
|
||||
// Forums might provide feeds, though that's optional *facepalm*
|
||||
// Let's check if there is a valid feed available
|
||||
$headers = get_headers($uri . '.xml');
|
||||
|
||||
if($headers[0] === 'HTTP/1.1 200 OK') { // Heureka! It's a valid feed!
|
||||
return $this->collectExpandableDatas($uri);
|
||||
}
|
||||
|
||||
// No valid feed, so do it the hard way
|
||||
$html = getSimpleHTMLDOM($uri)
|
||||
or returnServerError('Could not request ' . $this->getInput('uri') . '!');
|
||||
|
||||
$limit = $this->getInput('limit');
|
||||
|
||||
// Determine if this is a topic or a forum
|
||||
switch(true) {
|
||||
case $this->isTopic($html):
|
||||
$this->collectTopic($html, $limit);
|
||||
break;
|
||||
case $this->isForum($html);
|
||||
$this->collectForum($html);
|
||||
break;
|
||||
default:
|
||||
returnClientError('Unknown type!');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private function isForum($html){
|
||||
return !is_null($html->find('div[data-controller*=forums.front.forum.forumPage]', 0))
|
||||
|| !is_null($html->find(static::FORUM_TYPE_TABLE_FILTER, 0));
|
||||
}
|
||||
|
||||
private function isTopic($html){
|
||||
return !is_null($html->find('div[data-controller*=core.front.core.commentFeed]', 0))
|
||||
|| !is_null($html->find(static::TOPIC_TYPE_DIV, 0));
|
||||
}
|
||||
|
||||
private function collectForum($html){
|
||||
// There are multiple forum designs in use (depends on version?)
|
||||
// 1 - Uses an ordered list (based on https://invisioncommunity.com/forums)
|
||||
// 2 - Uses a table (based on https://onehallyu.com)
|
||||
|
||||
switch(true) {
|
||||
case !is_null($html->find(static::FORUM_TYPE_LIST_FILTER, 0)):
|
||||
$this->collectForumList($html);
|
||||
break;
|
||||
case !is_null($html->find(static::FORUM_TYPE_TABLE_FILTER, 0)):
|
||||
$this->collectForumTable($html);
|
||||
break;
|
||||
default:
|
||||
returnClientError('Unknown forum format!');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private function collectForumList($html){
|
||||
foreach($html->find(static::FORUM_TYPE_LIST_FILTER, 0)->children() as $row) {
|
||||
// Columns: Title, Statistics, Last modified
|
||||
$item = array();
|
||||
|
||||
$item['uri'] = $row->find('a', 0)->href;
|
||||
$item['title'] = $row->find('a', 0)->title;
|
||||
$item['author'] = $row->find('a', 1)->innertext;
|
||||
$item['timestamp'] = strtotime($row->find('time', 0)->getAttribute('datetime'));
|
||||
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
private function collectForumTable($html){
|
||||
foreach($html->find(static::FORUM_TYPE_TABLE_FILTER, 0)->children() as $row) {
|
||||
// Columns: Icon, Content, Preview, Statistics, Last modified
|
||||
$item = array();
|
||||
|
||||
// Skip header row
|
||||
if(!is_null($row->find('th', 0))) continue;
|
||||
|
||||
$item['uri'] = $row->find('a', 0)->href;
|
||||
$item['title'] = $row->find('.title', 0)->plaintext;
|
||||
$item['timestamp'] = strtotime($row->find('[itemprop=dateCreated]', 0)->plaintext);
|
||||
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
private function collectTopic($html, $limit){
|
||||
// There are multiple topic designs in use (depends on version?)
|
||||
// 1 - Uses articles (based on https://invisioncommunity.com/forums)
|
||||
// 2 - Uses divs (based on https://onehallyu.com)
|
||||
|
||||
switch(true) {
|
||||
case !is_null($html->find(static::TOPIC_TYPE_ARTICLE, 0)):
|
||||
$this->collectTopicHistory($html, $limit, 'collectTopicArticle');
|
||||
break;
|
||||
case !is_null($html->find(static::TOPIC_TYPE_DIV, 0)):
|
||||
$this->collectTopicHistory($html, $limit, 'collectTopicDiv');
|
||||
break;
|
||||
default:
|
||||
returnClientError('Unknown topic format!');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private function collectTopicHistory($html, $limit, $callback){
|
||||
// Make sure the callback is valid!
|
||||
if(!method_exists($this, $callback))
|
||||
returnServerError('Unknown function (\'' . $callback . '\')!');
|
||||
|
||||
$next = null; // Holds the URI of the next page
|
||||
|
||||
while(true) {
|
||||
$next = $this->$callback($html, is_null($next));
|
||||
|
||||
if(is_null($next) || ($limit > 0 && count($this->items) >= $limit)) {
|
||||
break;
|
||||
}
|
||||
|
||||
$html = getSimpleHTMLDOMCached($next);
|
||||
}
|
||||
|
||||
// We might have more items than specified, remove excess
|
||||
$this->items = array_slice($this->items, 0, $limit);
|
||||
}
|
||||
|
||||
private function collectTopicArticle($html, $firstrun = true){
|
||||
$title = $html->find('h1.ipsType_pageTitle', 0)->plaintext;
|
||||
|
||||
// Are we on last page?
|
||||
if($firstrun && !is_null($html->find('.ipsPagination', 0))) {
|
||||
$last = $html->find('.ipsPagination_last a', 0)->{'data-page'};
|
||||
$active = $html->find('.ipsPagination_active a', 0)->{'data-page'};
|
||||
|
||||
if($active !== $last) {
|
||||
// Load last page into memory (cached)
|
||||
$html = getSimpleHTMLDOMCached($html->find('.ipsPagination_last a', 0)->href);
|
||||
}
|
||||
}
|
||||
|
||||
foreach(array_reverse($html->find(static::TOPIC_TYPE_ARTICLE)) as $article) {
|
||||
$item = array();
|
||||
|
||||
$item['uri'] = $article->find('time', 0)->parent()->href;
|
||||
$item['author'] = $article->find('aside a', 0)->plaintext;
|
||||
$item['title'] = $item['author'] . ' - ' . $title;
|
||||
$item['timestamp'] = strtotime($article->find('time', 0)->getAttribute('datetime'));
|
||||
|
||||
$content = $article->find('[data-role=commentContent]', 0);
|
||||
$content = $this->scaleImages($content);
|
||||
$item['content'] = $this->fixContent($content);
|
||||
$item['enclosures'] = $this->findImages($article->find('[data-role=commentContent]', 0)) ?: null;
|
||||
|
||||
$this->items[] = $item;
|
||||
}
|
||||
|
||||
// Return whatever page comes next (previous, as we add in inverse order)
|
||||
// Do we have a previous page? (inactive means no)
|
||||
if(!is_null($html->find('li[class=ipsPagination_prev ipsPagination_inactive]', 0))) {
|
||||
return null; // No, or no more
|
||||
} elseif(!is_null($html->find('li[class=ipsPagination_prev]', 0))) {
|
||||
return $html->find('.ipsPagination_prev a', 0)->href;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function collectTopicDiv($html, $firstrun = true){
|
||||
$title = $html->find('h1.ipsType_pagetitle', 0)->plaintext;
|
||||
|
||||
// Are we on last page?
|
||||
if($firstrun && !is_null($html->find('.pagination', 0))) {
|
||||
|
||||
$active = $html->find('li[class=page active]', 0)->plaintext;
|
||||
|
||||
// There are two ways the 'last' page is displayed:
|
||||
// - With a distict 'last' button (only if there are enough pages)
|
||||
// - With a button for each page (use last button)
|
||||
if(!is_null($html->find('li.last', 0))) {
|
||||
$last = $html->find('li.last a', 0);
|
||||
} else {
|
||||
$last = $html->find('li[class=page] a', -1);
|
||||
}
|
||||
|
||||
if($active !== $last->plaintext) {
|
||||
// Load last page into memory (cached)
|
||||
$html = getSimpleHTMLDOMCached($last->href);
|
||||
}
|
||||
}
|
||||
|
||||
foreach(array_reverse($html->find(static::TOPIC_TYPE_DIV)) as $article) {
|
||||
$item = array();
|
||||
|
||||
$item['uri'] = $article->find('a[rel=bookmark]', 0)->href;
|
||||
$item['author'] = $article->find('.author', 0)->plaintext;
|
||||
$item['title'] = $item['author'] . ' - ' . $title;
|
||||
$item['timestamp'] = strtotime($article->find('.published', 0)->getAttribute('title'));
|
||||
|
||||
$content = $article->find('[itemprop=commentText]', 0);
|
||||
$content = $this->scaleImages($content);
|
||||
$item['content'] = $this->fixContent($content);
|
||||
|
||||
$item['enclosures'] = $this->findImages($article->find('.post_body', 0)) ?: null;
|
||||
|
||||
$this->items[] = $item;
|
||||
}
|
||||
|
||||
// Return whatever page comes next (previous, as we add in inverse order)
|
||||
// Do we have a previous page?
|
||||
if(!is_null($html->find('li.prev', 0))) {
|
||||
return $html->find('li.prev a', 0)->href;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Returns all images from the provide HTML DOM */
|
||||
private function findImages($html){
|
||||
$images = array();
|
||||
|
||||
foreach($html->find('img') as $img) {
|
||||
$images[] = $img->src;
|
||||
}
|
||||
|
||||
return $images;
|
||||
}
|
||||
|
||||
/** Sets the maximum width and height for all images */
|
||||
private function scaleImages($html, $width = 400, $height = 400){
|
||||
foreach($html->find('img') as $img) {
|
||||
$img->style = "max-width: {$width}px; max-height: {$height}px;";
|
||||
}
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
/** Removes all unnecessary tags and adds formatting */
|
||||
private function fixContent($html){
|
||||
|
||||
// Restore quote highlighting
|
||||
foreach($html->find('blockquote') as $quote) {
|
||||
$quote->style = <<<EOD
|
||||
padding: 0px 15px;
|
||||
border-width: 1px 1px 1px 2px;
|
||||
border-style: solid;
|
||||
border-color: #ededed #e8e8e8 #dbdbdb #666666;
|
||||
background: #fbfbfb;
|
||||
EOD;
|
||||
}
|
||||
|
||||
// Remove unnecessary tags
|
||||
$content = strip_tags(
|
||||
$html->innertext,
|
||||
'<p><a><img><ol><ul><li><table><tr><th><td><strong><blockquote><br><hr><h>'
|
||||
);
|
||||
|
||||
return $content;
|
||||
}
|
||||
}
|
@@ -1,11 +1,11 @@
|
||||
<?php
|
||||
class IdenticaBridge extends BridgeAbstract {
|
||||
|
||||
const MAINTAINER = "mitsukarenai";
|
||||
const NAME = "Identica Bridge";
|
||||
const URI = "https://identi.ca/";
|
||||
const MAINTAINER = 'mitsukarenai';
|
||||
const NAME = 'Identica Bridge';
|
||||
const URI = 'https://identi.ca/';
|
||||
const CACHE_TIMEOUT = 300; // 5min
|
||||
const DESCRIPTION = "Returns user timelines";
|
||||
const DESCRIPTION = 'Returns user timelines';
|
||||
|
||||
const PARAMETERS = array( array(
|
||||
'u' => array(
|
||||
@@ -20,19 +20,33 @@ class IdenticaBridge extends BridgeAbstract{
|
||||
|
||||
foreach($html->find('li.major') as $dent) {
|
||||
$item = array();
|
||||
$item['uri'] = html_entity_decode($dent->find('a', 0)->href); // get dent link
|
||||
$item['timestamp'] = strtotime($dent->find('abbr.easydate', 0)->plaintext); // extract dent timestamp
|
||||
$item['content'] = trim($dent->find('div.activity-content', 0)->innertext); // extract dent text
|
||||
|
||||
// get dent link
|
||||
$item['uri'] = html_entity_decode($dent->find('a', 0)->href);
|
||||
|
||||
// extract dent timestamp
|
||||
$item['timestamp'] = strtotime($dent->find('abbr.easydate', 0)->plaintext);
|
||||
|
||||
// extract dent text
|
||||
$item['content'] = trim($dent->find('div.activity-content', 0)->innertext);
|
||||
$item['title'] = $this->getInput('u') . ' | ' . $item['content'];
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
if(!is_null($this->getInput('u'))) {
|
||||
return $this->getInput('u') . ' - Identica Bridge';
|
||||
}
|
||||
|
||||
return parent::getName();
|
||||
}
|
||||
|
||||
public function getURI(){
|
||||
if(!is_null($this->getInput('u'))) {
|
||||
return self::URI . urlencode($this->getInput('u'));
|
||||
}
|
||||
|
||||
return parent::getURI();
|
||||
}
|
||||
}
|
||||
|
@@ -1,17 +1,47 @@
|
||||
<?php
|
||||
class InstagramBridge extends BridgeAbstract {
|
||||
|
||||
const MAINTAINER = "pauder";
|
||||
const NAME = "Instagram Bridge";
|
||||
const URI = "http://instagram.com/";
|
||||
const DESCRIPTION = "Returns the newest images";
|
||||
const MAINTAINER = 'pauder';
|
||||
const NAME = 'Instagram Bridge';
|
||||
const URI = 'https://instagram.com/';
|
||||
const DESCRIPTION = 'Returns the newest images';
|
||||
|
||||
const PARAMETERS = array( array(
|
||||
const PARAMETERS = array(
|
||||
array(
|
||||
'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
|
||||
),
|
||||
'media_type' => array(
|
||||
'name' => 'Media type',
|
||||
'type' => 'list',
|
||||
'required' => false,
|
||||
'values' => array(
|
||||
'Both' => 'all',
|
||||
'Video' => 'video',
|
||||
'Picture' => 'picture'
|
||||
),
|
||||
'defaultValue' => 'all'
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
public function collectData(){
|
||||
$html = getSimpleHTMLDOM($this->getURI())
|
||||
@@ -19,15 +49,13 @@ class InstagramBridge extends BridgeAbstract{
|
||||
|
||||
$innertext = null;
|
||||
|
||||
foreach($html->find('script') as $script)
|
||||
{
|
||||
foreach($html->find('script') as $script) {
|
||||
if('' === $script->innertext) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$pos = strpos(trim($script->innertext), 'window._sharedData');
|
||||
if (0 !== $pos)
|
||||
{
|
||||
if(0 !== $pos) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -38,34 +66,54 @@ class InstagramBridge extends BridgeAbstract{
|
||||
$json = trim(substr($innertext, $pos + 18), ' =;');
|
||||
$data = json_decode($json);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
$userMedia = $data->entry_data->ProfilePage[0]->user->media->nodes;
|
||||
|
||||
foreach($userMedia as $media)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
$item = array();
|
||||
$item['uri'] = self::URI.'p/'.$media->code.'/';
|
||||
$item['content'] = '<img src="' . htmlentities($media->display_src) . '" />';
|
||||
if (isset($media->caption))
|
||||
{
|
||||
$item['title'] = $media->caption;
|
||||
$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_src);
|
||||
$item['title'] = basename($media->display_url);
|
||||
}
|
||||
$item['timestamp'] = $media->date;
|
||||
$item['timestamp'] = $media->taken_at_timestamp;
|
||||
$this->items[] = $item;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
if(!is_null($this->getInput('u'))) {
|
||||
return $this->getInput('u') . ' - Instagram Bridge';
|
||||
}
|
||||
|
||||
public function getURI(){
|
||||
return self::URI.urlencode($this->getInput('u'));
|
||||
}
|
||||
return parent::getName();
|
||||
}
|
||||
|
||||
public function getURI(){
|
||||
if(!is_null($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();
|
||||
}
|
||||
}
|
||||
|
@@ -108,20 +108,20 @@ class IsoHuntBridge extends BridgeAbstract{
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'By "Torrent" category':
|
||||
$uri .= $this->build_category_uri(
|
||||
$uri .= $this->buildCategoryUri(
|
||||
$this->getInput('torrent_category'),
|
||||
$this->getInput('torrent_popularity')
|
||||
);
|
||||
break;
|
||||
|
||||
case 'Search torrent by name':
|
||||
$category = $this->getInput('search_category');
|
||||
$uri .= $this->build_category_uri($category);
|
||||
$uri .= $this->buildCategoryUri($category);
|
||||
if($category !== 'movies')
|
||||
$uri .= '&ihq=' . urlencode($this->getInput('search_name'));
|
||||
break;
|
||||
|
||||
default: parent::getURI();
|
||||
}
|
||||
|
||||
return $uri;
|
||||
@@ -130,71 +130,68 @@ class IsoHuntBridge extends BridgeAbstract{
|
||||
public function getName(){
|
||||
switch($this->queriedContext) {
|
||||
case 'By "Latest" category':
|
||||
$categoryName =
|
||||
array_search(
|
||||
$categoryName = array_search(
|
||||
$this->getInput('latest_category'),
|
||||
self::PARAMETERS['By "Latest" category']['latest_category']['values']
|
||||
);
|
||||
$name = 'Latest ' . $categoryName . ' - ' . self::NAME;
|
||||
break;
|
||||
|
||||
case 'By "Torrent" category':
|
||||
$categoryName =
|
||||
array_search(
|
||||
$categoryName = array_search(
|
||||
$this->getInput('torrent_category'),
|
||||
self::PARAMETERS['By "Torrent" category']['torrent_category']['values']
|
||||
);
|
||||
$name = 'Category: ' . $categoryName . ' - ' . self::NAME;
|
||||
break;
|
||||
|
||||
case 'Search torrent by name':
|
||||
$categoryName =
|
||||
array_search(
|
||||
$categoryName = array_search(
|
||||
$this->getInput('search_category'),
|
||||
self::PARAMETERS['Search torrent by name']['search_category']['values']
|
||||
);
|
||||
$name = 'Search: "' . $this->getInput('search_name') . '" in category: ' . $categoryName . ' - ' . self::NAME;
|
||||
$name = 'Search: "'
|
||||
. $this->getInput('search_name')
|
||||
. '" in category: '
|
||||
. $categoryName . ' - '
|
||||
. self::NAME;
|
||||
break;
|
||||
default: return parent::getName();
|
||||
}
|
||||
|
||||
return $name;
|
||||
}
|
||||
|
||||
|
||||
public function collectData(){
|
||||
$html = $this->load_html($this->getURI());
|
||||
$html = $this->loadHtml($this->getURI());
|
||||
|
||||
switch($this->queriedContext) {
|
||||
case 'By "Latest" category':
|
||||
switch($this->getInput('latest_category')) {
|
||||
case 'hot_torrents':
|
||||
$this->get_latest_hot_torrents($html);
|
||||
$this->getLatestHotTorrents($html);
|
||||
break;
|
||||
case 'news':
|
||||
$this->get_latest_news($html);
|
||||
$this->getLatestNews($html);
|
||||
break;
|
||||
case 'releases':
|
||||
case 'torrents':
|
||||
$this->get_latest_torrents($html);
|
||||
$this->getLatestTorrents($html);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'By "Torrent" category':
|
||||
if($this->getInput('torrent_category') === 'movies') {
|
||||
// This one is special (content wise)
|
||||
$this->get_movie_torrents($html);
|
||||
$this->getMovieTorrents($html);
|
||||
} else {
|
||||
$this->get_latest_torrents($html);
|
||||
$this->getLatestTorrents($html);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'Search torrent by name':
|
||||
if($this->getInput('search_category') === 'movies') {
|
||||
// This one is special (content wise)
|
||||
$this->get_movie_torrents($html);
|
||||
$this->getMovieTorrents($html);
|
||||
} else {
|
||||
$this->get_latest_torrents($html);
|
||||
$this->getLatestTorrents($html);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -202,7 +199,7 @@ class IsoHuntBridge extends BridgeAbstract{
|
||||
|
||||
#region Helper functions for "Movie Torrents"
|
||||
|
||||
private function get_movie_torrents($html){
|
||||
private function getMovieTorrents($html){
|
||||
$container = $html->find('div#w0', 0);
|
||||
if(!$container)
|
||||
returnServerError('Unable to find torrent container!');
|
||||
@@ -223,11 +220,11 @@ class IsoHuntBridge extends BridgeAbstract{
|
||||
|
||||
$item = array();
|
||||
|
||||
$item['uri'] = $this->fix_relative_uri($anchor->href);
|
||||
$item['uri'] = $this->fixRelativeUri($anchor->href);
|
||||
$item['title'] = $anchor->title;
|
||||
// $item['author'] =
|
||||
$item['timestamp'] = strtotime($date->plaintext);
|
||||
$item['content'] = $this->fix_relative_uri($torrent->innertext);
|
||||
$item['content'] = $this->fixRelativeUri($torrent->innertext);
|
||||
|
||||
$this->items[] = $item;
|
||||
}
|
||||
@@ -237,7 +234,7 @@ class IsoHuntBridge extends BridgeAbstract{
|
||||
|
||||
#region Helper functions for "Latest Hot Torrents"
|
||||
|
||||
private function get_latest_hot_torrents($html){
|
||||
private function getLatestHotTorrents($html){
|
||||
$container = $html->find('div#serps', 0);
|
||||
if(!$container)
|
||||
returnServerError('Unable to find torrent container!');
|
||||
@@ -275,7 +272,7 @@ class IsoHuntBridge extends BridgeAbstract{
|
||||
|
||||
#region Helper functions for "Latest News"
|
||||
|
||||
private function get_latest_news($html){
|
||||
private function getLatestNews($html){
|
||||
$container = $html->find('div#postcontainer', 0);
|
||||
if(!$container)
|
||||
returnServerError('Unable to find post container!');
|
||||
@@ -287,17 +284,17 @@ class IsoHuntBridge extends BridgeAbstract{
|
||||
foreach($posts as $post) {
|
||||
$item = array();
|
||||
|
||||
$item['uri'] = $this->latest_news_extract_uri($post);
|
||||
$item['title'] = $this->latest_news_extract_title($post);
|
||||
$item['author'] = $this->latest_news_extract_author($post);
|
||||
$item['timestamp'] = $this->latest_news_extract_timestamp($post);
|
||||
$item['content'] = $this->latest_news_extract_content($post);
|
||||
$item['uri'] = $this->latestNewsExtractUri($post);
|
||||
$item['title'] = $this->latestNewsExtractTitle($post);
|
||||
$item['author'] = $this->latestNewsExtractAuthor($post);
|
||||
$item['timestamp'] = $this->latestNewsExtractTimestamp($post);
|
||||
$item['content'] = $this->latestNewsExtractContent($post);
|
||||
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
private function latest_news_extract_author($post){
|
||||
private function latestNewsExtractAuthor($post){
|
||||
$author = $post->find('small', 0);
|
||||
if(!$author)
|
||||
returnServerError('Unable to find author!');
|
||||
@@ -308,7 +305,7 @@ class IsoHuntBridge extends BridgeAbstract{
|
||||
return $matches[1];
|
||||
}
|
||||
|
||||
private function latest_news_extract_timestamp($post){
|
||||
private function latestNewsExtractTimestamp($post){
|
||||
$date = $post->find('small', 0);
|
||||
if(!$date)
|
||||
returnServerError('Unable to find date!');
|
||||
@@ -326,7 +323,7 @@ class IsoHuntBridge extends BridgeAbstract{
|
||||
return $timestamp;
|
||||
}
|
||||
|
||||
private function latest_news_extract_title($post){
|
||||
private function latestNewsExtractTitle($post){
|
||||
$title = $post->find('a', 0);
|
||||
if(!$title)
|
||||
returnServerError('Unable to find title!');
|
||||
@@ -334,7 +331,7 @@ class IsoHuntBridge extends BridgeAbstract{
|
||||
return $title->plaintext;
|
||||
}
|
||||
|
||||
private function latest_news_extract_uri($post){
|
||||
private function latestNewsExtractUri($post){
|
||||
$uri = $post->find('a', 0);
|
||||
if(!$uri)
|
||||
returnServerError('Unable to find uri!');
|
||||
@@ -342,7 +339,7 @@ class IsoHuntBridge extends BridgeAbstract{
|
||||
return $uri->href;
|
||||
}
|
||||
|
||||
private function latest_news_extract_content($post){
|
||||
private function latestNewsExtractContent($post){
|
||||
$content = $post->find('div', 0);
|
||||
if(!$content)
|
||||
returnServerError('Unable to find content!');
|
||||
@@ -364,7 +361,7 @@ class IsoHuntBridge extends BridgeAbstract{
|
||||
|
||||
#region Helper functions for "Latest Torrents", "Latest Releases" and "Torrent Category"
|
||||
|
||||
private function get_latest_torrents($html){
|
||||
private function getLatestTorrents($html){
|
||||
$container = $html->find('div#serps', 0);
|
||||
if(!$container)
|
||||
returnServerError('Unable to find torrent container!');
|
||||
@@ -376,17 +373,17 @@ class IsoHuntBridge extends BridgeAbstract{
|
||||
foreach($torrents as $torrent) {
|
||||
$item = array();
|
||||
|
||||
$item['uri'] = $this->latest_torrents_extract_uri($torrent);
|
||||
$item['title'] = $this->latest_torrents_extract_title($torrent);
|
||||
$item['author'] = $this->latest_torrents_extract_author($torrent);
|
||||
$item['timestamp'] = $this->latest_torrents_extract_timestamp($torrent);
|
||||
$item['uri'] = $this->latestTorrentsExtractUri($torrent);
|
||||
$item['title'] = $this->latestTorrentsExtractTitle($torrent);
|
||||
$item['author'] = $this->latestTorrentsExtractAuthor($torrent);
|
||||
$item['timestamp'] = $this->latestTorrentsExtractTimestamp($torrent);
|
||||
$item['content'] = ''; // There is no valuable content
|
||||
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
private function latest_torrents_extract_title($torrent){
|
||||
private function latestTorrentsExtractTitle($torrent){
|
||||
$cell = $torrent->find('td.title-row', 0);
|
||||
if(!$cell)
|
||||
returnServerError('Unable to find title cell!');
|
||||
@@ -398,7 +395,7 @@ class IsoHuntBridge extends BridgeAbstract{
|
||||
return $title->plaintext;
|
||||
}
|
||||
|
||||
private function latest_torrents_extract_uri($torrent){
|
||||
private function latestTorrentsExtractUri($torrent){
|
||||
$cell = $torrent->find('td.title-row', 0);
|
||||
if(!$cell)
|
||||
returnServerError('Unable to find title cell!');
|
||||
@@ -407,10 +404,10 @@ class IsoHuntBridge extends BridgeAbstract{
|
||||
if(!$uri)
|
||||
returnServerError('Unable to find uri!');
|
||||
|
||||
return $this->fix_relative_uri($uri->href);
|
||||
return $this->fixRelativeUri($uri->href);
|
||||
}
|
||||
|
||||
private function latest_torrents_extract_author($torrent){
|
||||
private function latestTorrentsExtractAuthor($torrent){
|
||||
$cell = $torrent->find('td.user-row', 0);
|
||||
if(!$cell)
|
||||
return; // No author
|
||||
@@ -422,7 +419,7 @@ class IsoHuntBridge extends BridgeAbstract{
|
||||
return $user->plaintext;
|
||||
}
|
||||
|
||||
private function latest_torrents_extract_timestamp($torrent){
|
||||
private function latestTorrentsExtractTimestamp($torrent){
|
||||
$cell = $torrent->find('td.date-row', 0);
|
||||
if(!$cell)
|
||||
returnServerError('Unable to find date cell!');
|
||||
@@ -434,7 +431,7 @@ class IsoHuntBridge extends BridgeAbstract{
|
||||
|
||||
#region Generic helper functions
|
||||
|
||||
private function load_html($uri){
|
||||
private function loadHtml($uri){
|
||||
$html = getSimpleHTMLDOM($uri);
|
||||
if(!$html)
|
||||
returnServerError('Unable to load ' . $uri . '!');
|
||||
@@ -442,11 +439,11 @@ class IsoHuntBridge extends BridgeAbstract{
|
||||
return $html;
|
||||
}
|
||||
|
||||
private function fix_relative_uri($uri){
|
||||
private function fixRelativeUri($uri){
|
||||
return preg_replace('/\//i', self::URI, $uri, 1);
|
||||
}
|
||||
|
||||
private function build_category_uri($category, $order_popularity = false){
|
||||
private function buildCategoryUri($category, $order_popularity = false){
|
||||
switch($category) {
|
||||
case 'anime': $index = 1; break;
|
||||
case 'software' : $index = 2; break;
|
||||
|
@@ -15,7 +15,7 @@ class JapanExpoBridge extends BridgeAbstract {
|
||||
|
||||
public function collectData(){
|
||||
|
||||
function french_pubdate_to_timestamp($date_to_parse) {
|
||||
function frenchPubDateToTimestamp($date_to_parse) {
|
||||
return strtotime(
|
||||
strtr(
|
||||
strtolower(str_replace('Publié le ', '', $date_to_parse)),
|
||||
@@ -53,6 +53,7 @@ class JapanExpoBridge extends BridgeAbstract {
|
||||
$url = $element->href;
|
||||
$thumbnail = 'http://s.japan-expo.com/katana/images/JES049/paris.png';
|
||||
preg_match('/url\(([^)]+)\)/', $element->find('img.rspvimgset', 0)->style, $img_search_result);
|
||||
|
||||
if(count($img_search_result) >= 2)
|
||||
$thumbnail = trim($img_search_result[1], "'");
|
||||
|
||||
@@ -68,13 +69,23 @@ class JapanExpoBridge extends BridgeAbstract {
|
||||
$title = $title_html->plaintext;
|
||||
$headings = $title_html->next_sibling()->outertext;
|
||||
$article = $article_html->find('div.content', 0)->innertext;
|
||||
$article = preg_replace_callback('/<img [^>]+ style="[^\(]+\(\'([^\']+)\'[^>]+>/i', $convert_article_images, $article);
|
||||
$article = preg_replace_callback(
|
||||
'/<img [^>]+ style="[^\(]+\(\'([^\']+)\'[^>]+>/i',
|
||||
$convert_article_images,
|
||||
$article);
|
||||
|
||||
$content = $headings . $article;
|
||||
} else {
|
||||
$date_text = $element->find('span.date', 0)->plaintext;
|
||||
$timestamp = french_pubdate_to_timestamp($date_text);
|
||||
$timestamp = frenchPubDateToTimestamp($date_text);
|
||||
$title = trim($element->find('span._title', 0)->plaintext);
|
||||
$content = '<img src="'.$thumbnail.'"></img><br />'.$date_text.'<br /><a href="'.$url.'">Lire l\'article</a>';
|
||||
$content = '<img src="'
|
||||
. $thumbnail
|
||||
. '"></img><br />'
|
||||
. $date_text
|
||||
. '<br /><a href="'
|
||||
. $url
|
||||
. '">Lire l\'article</a>';
|
||||
}
|
||||
|
||||
$item = array();
|
||||
|
123
bridges/KATBridge.php
Normal file
123
bridges/KATBridge.php
Normal file
@@ -0,0 +1,123 @@
|
||||
<?php
|
||||
class KATBridge extends BridgeAbstract {
|
||||
const MAINTAINER = 'niawag';
|
||||
const NAME = 'KickassTorrents';
|
||||
const URI = 'https://katcr.co/new/';
|
||||
const DESCRIPTION = 'Returns results for the keywords. You can put several
|
||||
list of keywords by separating them with a semicolon (e.g. "one show;another
|
||||
show"). Category based search needs the category number as input. User based
|
||||
search takes the Uploader ID: see KAT URL for user feed. Search can be done in a specified category';
|
||||
|
||||
const PARAMETERS = array( array(
|
||||
'q' => array(
|
||||
'name' => 'keywords, separated by semicolons',
|
||||
'exampleValue' => 'first list;second list;…',
|
||||
'required' => true
|
||||
),
|
||||
'crit' => array(
|
||||
'type' => 'list',
|
||||
'name' => 'Search type',
|
||||
'values' => array(
|
||||
'search' => 'search',
|
||||
'category' => 'cat',
|
||||
'user' => 'usr'
|
||||
)
|
||||
),
|
||||
'cat_check' => array(
|
||||
'type' => 'checkbox',
|
||||
'name' => 'Specify category for normal search ?',
|
||||
),
|
||||
'cat' => array(
|
||||
'name' => 'Category number',
|
||||
'exampleValue' => '100, 200… See KAT for category number'
|
||||
),
|
||||
'trusted' => array(
|
||||
'type' => 'checkbox',
|
||||
'name' => 'Only get results from Elite or Verified uploaders ?',
|
||||
),
|
||||
));
|
||||
public function collectData(){
|
||||
function parseDateTimestamp($element){
|
||||
$guessedDate = strptime($element, '%d-%m-%Y %H:%M:%S');
|
||||
$timestamp = mktime(
|
||||
$guessedDate['tm_hour'],
|
||||
$guessedDate['tm_min'],
|
||||
$guessedDate['tm_sec'],
|
||||
$guessedDate['tm_mon'] + 1,
|
||||
$guessedDate['tm_mday'],
|
||||
$guessedDate['tm_year'] + 1900);
|
||||
return $timestamp;
|
||||
}
|
||||
$catBool = $this->getInput('cat_check');
|
||||
if($catBool) {
|
||||
$catNum = $this->getInput('cat');
|
||||
}
|
||||
$critList = $this->getInput('crit');
|
||||
$trustedBool = $this->getInput('trusted');
|
||||
$keywordsList = explode(';', $this->getInput('q'));
|
||||
foreach($keywordsList as $keywords) {
|
||||
switch($critList) {
|
||||
case 'search':
|
||||
if($catBool == false) {
|
||||
$html = getSimpleHTMLDOM(
|
||||
self::URI .
|
||||
'torrents-search.php?search=' .
|
||||
rawurlencode($keywords)
|
||||
) or returnServerError('Could not request KAT.');
|
||||
} else {
|
||||
$html = getSimpleHTMLDOM(
|
||||
self::URI .
|
||||
'torrents-search.php?search=' .
|
||||
rawurlencode($keywords) .
|
||||
'&cat=' .
|
||||
rawurlencode($catNum)
|
||||
) or returnServerError('Could not request KAT.');
|
||||
}
|
||||
break;
|
||||
case 'cat':
|
||||
$html = getSimpleHTMLDOM(
|
||||
self::URI .
|
||||
'torrents.php?cat=' .
|
||||
rawurlencode($keywords)
|
||||
) or returnServerError('Could not request KAT.');
|
||||
break;
|
||||
case 'usr':
|
||||
$html = getSimpleHTMLDOM(
|
||||
self::URI .
|
||||
'account-details.php?id=' .
|
||||
rawurlencode($keywords)
|
||||
) or returnServerError('Could not request KAT.');
|
||||
break;
|
||||
}
|
||||
if ($html->find('table.ttable_headinner', 0) == false)
|
||||
returnServerError('No result for query ' . $keywords);
|
||||
foreach($html->find('tr.t-row') as $element) {
|
||||
if(!$trustedBool
|
||||
|| !is_null($element->find('i[title="Elite Uploader"]', 0))
|
||||
|| !is_null($element->find('i[title="Verified Uploader"]', 0))) {
|
||||
$item = array();
|
||||
$item['uri'] = self::URI . $element->find('a', 2)->href;
|
||||
$item['id'] = self::URI . $element->find('a.cellMainLink', 0)->href;
|
||||
$item['timestamp'] = parseDateTimestamp($element->find('td', 2)->plaintext);
|
||||
$item['author'] = $element->find('a.plain', 0)->plaintext;
|
||||
$item['title'] = $element->find('a.cellMainLink', 0)->plaintext;
|
||||
$item['seeders'] = (int)$element->find('td', 3)->plaintext;
|
||||
$item['leechers'] = (int)$element->find('td', 4)->plaintext;
|
||||
$item['size'] = $element->find('td', 1)->plaintext;
|
||||
$item['content'] = $item['title']
|
||||
. '<br>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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
150
bridges/KernelBugTrackerBridge.php
Normal file
150
bridges/KernelBugTrackerBridge.php
Normal file
@@ -0,0 +1,150 @@
|
||||
<?php
|
||||
class KernelBugTrackerBridge extends BridgeAbstract {
|
||||
|
||||
const NAME = 'Kernel Bug Tracker';
|
||||
const URI = 'https://bugzilla.kernel.org';
|
||||
const DESCRIPTION = 'Returns feeds for bug comments';
|
||||
const MAINTAINER = 'logmanoriginal';
|
||||
const PARAMETERS = array(
|
||||
'Bug comments' => array(
|
||||
'id' => array(
|
||||
'name' => 'Bug tracking ID',
|
||||
'type' => 'number',
|
||||
'required' => true,
|
||||
'title' => 'Insert bug tracking ID',
|
||||
'exampleValue' => 121241
|
||||
),
|
||||
'limit' => array(
|
||||
'name' => 'Number of comments to return',
|
||||
'type' => 'number',
|
||||
'required' => false,
|
||||
'title' => 'Specify number of comments to return',
|
||||
'defaultValue' => -1
|
||||
),
|
||||
'sorting' => array(
|
||||
'name' => 'Sorting',
|
||||
'type' => 'list',
|
||||
'required' => false,
|
||||
'title' => 'Defines the sorting order of the comments returned',
|
||||
'defaultValue' => 'of',
|
||||
'values' => array(
|
||||
'Oldest first' => 'of',
|
||||
'Latest first' => 'lf'
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
private $bugid = '';
|
||||
private $bugdesc = '';
|
||||
|
||||
public function collectData(){
|
||||
$limit = $this->getInput('limit');
|
||||
$sorting = $this->getInput('sorting');
|
||||
|
||||
// We use the print preview page for simplicity
|
||||
$html = getSimpleHTMLDOMCached($this->getURI() . '&format=multiple',
|
||||
86400,
|
||||
null,
|
||||
null,
|
||||
true,
|
||||
true,
|
||||
DEFAULT_TARGET_CHARSET,
|
||||
false, // Do NOT remove line breaks
|
||||
DEFAULT_BR_TEXT,
|
||||
DEFAULT_SPAN_TEXT);
|
||||
|
||||
if($html === false)
|
||||
returnServerError('Failed to load page!');
|
||||
|
||||
// Store header information into private members
|
||||
$this->bugid = $html->find('#bugzilla-body', 0)->find('a', 0)->innertext;
|
||||
$this->bugdesc = $html->find('table.bugfields', 0)->find('tr', 0)->find('td', 0)->innertext;
|
||||
|
||||
// Get and limit comments
|
||||
$comments = $html->find('div.bz_comment');
|
||||
|
||||
if($limit > 0 && count($comments) > $limit) {
|
||||
$comments = array_slice($comments, count($comments) - $limit, $limit);
|
||||
}
|
||||
|
||||
// Order comments
|
||||
switch($sorting) {
|
||||
case 'lf': $comments = array_reverse($comments, true);
|
||||
case 'of':
|
||||
default: // Nothing to do, keep original order
|
||||
}
|
||||
|
||||
foreach($comments as $comment) {
|
||||
$comment = $this->inlineStyles($comment);
|
||||
|
||||
$item = array();
|
||||
$item['uri'] = $this->getURI() . '#' . $comment->id;
|
||||
$item['author'] = $comment->find('span.bz_comment_user', 0)->innertext;
|
||||
$item['title'] = $comment->find('span.bz_comment_number', 0)->find('a', 0)->innertext;
|
||||
$item['timestamp'] = strtotime($comment->find('span.bz_comment_time', 0)->innertext);
|
||||
$item['content'] = $comment->find('pre.bz_comment_text', 0)->innertext;
|
||||
|
||||
// Fix line breaks (they use LF)
|
||||
$item['content'] = str_replace("\n", '<br>', $item['content']);
|
||||
|
||||
// Fix relative URIs
|
||||
$item['content'] = $this->replaceRelativeURI($item['content']);
|
||||
|
||||
$this->items[] = $item;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function getURI(){
|
||||
switch($this->queriedContext) {
|
||||
case 'Bug comments':
|
||||
return parent::getURI()
|
||||
. '/show_bug.cgi?id='
|
||||
. $this->getInput('id');
|
||||
break;
|
||||
default: return parent::getURI();
|
||||
}
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
switch($this->queriedContext) {
|
||||
case 'Bug comments':
|
||||
return 'Bug '
|
||||
. $this->bugid
|
||||
. ' tracker for '
|
||||
. $this->bugdesc
|
||||
. ' - '
|
||||
. parent::getName();
|
||||
break;
|
||||
default: return parent::getName();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces all relative URIs with absolute ones
|
||||
*
|
||||
* @param string $content The source string
|
||||
* @return string Returns the source string with all relative URIs replaced
|
||||
* by absolute ones.
|
||||
*/
|
||||
private function replaceRelativeURI($content){
|
||||
return preg_replace('/href="(?!http)/', 'href="' . self::URI . '/', $content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds styles as attributes to tags with known classes
|
||||
*
|
||||
* @param object $html A simplehtmldom object
|
||||
* @return object Returns the original object with styles added as
|
||||
* attributes.
|
||||
*/
|
||||
private function inlineStyles($html){
|
||||
foreach($html->find('.bz_obsolete') as $element) {
|
||||
$element->style = 'text-decoration:line-through;';
|
||||
}
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
}
|
@@ -3,9 +3,9 @@ require_once('MoebooruBridge.php');
|
||||
|
||||
class KonachanBridge extends MoebooruBridge {
|
||||
|
||||
const MAINTAINER = "mitsukarenai";
|
||||
const NAME = "Konachan";
|
||||
const URI = "http://konachan.com/";
|
||||
const DESCRIPTION = "Returns images from given page";
|
||||
const MAINTAINER = 'mitsukarenai';
|
||||
const NAME = 'Konachan';
|
||||
const URI = 'http://konachan.com/';
|
||||
const DESCRIPTION = 'Returns images from given page';
|
||||
|
||||
}
|
||||
|
@@ -1,10 +1,10 @@
|
||||
<?php
|
||||
class KoreusBridge extends FeedExpander {
|
||||
|
||||
const MAINTAINER = "pit-fgfjiudghdf";
|
||||
const NAME = "Koreus";
|
||||
const URI = "http://www.koreus.com/";
|
||||
const DESCRIPTION = "Returns the newest posts from Koreus (full text)";
|
||||
const MAINTAINER = 'pit-fgfjiudghdf';
|
||||
const NAME = 'Koreus';
|
||||
const URI = 'http://www.koreus.com/';
|
||||
const DESCRIPTION = 'Returns the newest posts from Koreus (full text)';
|
||||
|
||||
protected function parseItem($item){
|
||||
$item = parent::parseItem($item);
|
||||
|
@@ -1,10 +1,10 @@
|
||||
<?php
|
||||
class KununuBridge extends BridgeAbstract {
|
||||
const MAINTAINER = "logmanoriginal";
|
||||
const NAME = "Kununu Bridge";
|
||||
const URI = "https://www.kununu.com/";
|
||||
const MAINTAINER = 'logmanoriginal';
|
||||
const NAME = 'Kununu Bridge';
|
||||
const URI = 'https://www.kununu.com/';
|
||||
const CACHE_TIMEOUT = 86400; // 24h
|
||||
const DESCRIPTION = "Returns the latest reviews for a company and site of your choice.";
|
||||
const DESCRIPTION = 'Returns the latest reviews for a company and site of your choice.';
|
||||
|
||||
const PARAMETERS = array(
|
||||
'global' => array(
|
||||
@@ -28,7 +28,6 @@ class KununuBridge extends BridgeAbstract {
|
||||
'title' => 'Activate to load full article'
|
||||
)
|
||||
),
|
||||
|
||||
array(
|
||||
'company' => array(
|
||||
'name' => 'Company',
|
||||
@@ -42,9 +41,12 @@ class KununuBridge extends BridgeAbstract {
|
||||
private $companyName = '';
|
||||
|
||||
public function getURI(){
|
||||
$company = $this->encode_umlauts(strtolower(str_replace(' ', '-', trim($this->getInput('company')))));
|
||||
if(!is_null($this->getInput('company')) && !is_null($this->getInput('site'))) {
|
||||
|
||||
$company = $this->fixCompanyName($this->getInput('company'));
|
||||
$site = $this->getInput('site');
|
||||
$section = '';
|
||||
|
||||
switch($site) {
|
||||
case 'at':
|
||||
case 'de':
|
||||
@@ -59,20 +61,27 @@ class KununuBridge extends BridgeAbstract {
|
||||
return self::URI . $site . '/' . $company . '/' . $section;
|
||||
}
|
||||
|
||||
return parent::getURI();
|
||||
}
|
||||
|
||||
function getName(){
|
||||
$company = $this->encode_umlauts(strtolower(str_replace(' ', '-', trim($this->getInput('company')))));
|
||||
if(!is_null($this->getInput('company'))) {
|
||||
$company = $this->fixCompanyName($this->getInput('company'));
|
||||
return ($this->companyName ?: $company) . ' - ' . self::NAME;
|
||||
}
|
||||
|
||||
return parent::getName();
|
||||
}
|
||||
|
||||
public function collectData(){
|
||||
$full = $this->getInput('full');
|
||||
|
||||
// Load page
|
||||
$html = getSimpleHTMLDOM($this->getURI());
|
||||
$html = getSimpleHTMLDOMCached($this->getURI());
|
||||
if(!$html)
|
||||
returnServerError('Unable to receive data from ' . $this->getURI() . '!');
|
||||
// Update name for this request
|
||||
$this->companyName = $this->extract_company_name($html);
|
||||
$this->companyName = $this->extractCompanyName($html);
|
||||
|
||||
// Find the section with all the panels (reviews)
|
||||
$section = $html->find('section.kununu-scroll-element', 0);
|
||||
@@ -88,15 +97,18 @@ class KununuBridge extends BridgeAbstract {
|
||||
foreach($articles as $article) {
|
||||
$item = array();
|
||||
|
||||
$item['author'] = $this->extract_article_author_position($article);
|
||||
$item['timestamp'] = $this->extract_article_date($article);
|
||||
$item['title'] = $this->extract_article_rating($article) . ' : ' . $this->extract_article_summary($article);
|
||||
$item['uri'] = $this->extract_article_uri($article);
|
||||
$item['author'] = $this->extractArticleAuthorPosition($article);
|
||||
$item['timestamp'] = $this->extractArticleDate($article);
|
||||
$item['title'] = $this->extractArticleRating($article)
|
||||
. ' : '
|
||||
. $this->extractArticleSummary($article);
|
||||
|
||||
$item['uri'] = $this->extractArticleUri($article);
|
||||
|
||||
if($full)
|
||||
$item['content'] = $this->extract_full_description($item['uri']);
|
||||
$item['content'] = $this->extractFullDescription($item['uri']);
|
||||
else
|
||||
$item['content'] = $this->extract_article_description($article);
|
||||
$item['content'] = $this->extractArticleDescription($article);
|
||||
|
||||
$this->items[] = $item;
|
||||
}
|
||||
@@ -105,14 +117,24 @@ class KununuBridge extends BridgeAbstract {
|
||||
/**
|
||||
* Fixes relative URLs in the given text
|
||||
*/
|
||||
private function fix_url($text){
|
||||
private function fixUrl($text){
|
||||
return preg_replace('/href=(\'|\")\//i', 'href="'.self::URI, $text);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns a fixed version of the provided company name
|
||||
*/
|
||||
private function fixCompanyName($company){
|
||||
$company = trim($company);
|
||||
$company = str_replace(' ', '-', $company);
|
||||
$company = strtolower($company);
|
||||
return $this->encodeUmlauts($company);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes unmlauts in the given text
|
||||
*/
|
||||
private function encode_umlauts($text){
|
||||
private function encodeUmlauts($text){
|
||||
$umlauts = Array("/ä/","/ö/","/ü/","/Ä/","/Ö/","/Ü/","/ß/");
|
||||
$replace = Array("ae","oe","ue","Ae","Oe","Ue","ss");
|
||||
|
||||
@@ -122,13 +144,9 @@ class KununuBridge extends BridgeAbstract {
|
||||
/**
|
||||
* Returns the company name from the review html
|
||||
*/
|
||||
private function extract_company_name($html){
|
||||
$panel = $html->find('div.panel', 0);
|
||||
if($panel === false)
|
||||
returnServerError('Cannot find panel for company name!');
|
||||
|
||||
$company_name = $panel->find('h1', 0);
|
||||
if($company_name === false)
|
||||
private function extractCompanyName($html){
|
||||
$company_name = $html->find('h1[itemprop=name]', 0);
|
||||
if(is_null($company_name))
|
||||
returnServerError('Cannot find company name!');
|
||||
|
||||
return $company_name->plaintext;
|
||||
@@ -137,21 +155,21 @@ class KununuBridge extends BridgeAbstract {
|
||||
/**
|
||||
* Returns the date from a given article
|
||||
*/
|
||||
private function extract_article_date($article){
|
||||
private function extractArticleDate($article){
|
||||
// They conviniently provide a time attribute for us :)
|
||||
$date = $article->find('time[itemprop=dtreviewed]', 0);
|
||||
if($date === false)
|
||||
$date = $article->find('meta[itemprop=dateCreated]', 0);
|
||||
if(is_null($date))
|
||||
returnServerError('Cannot find article date!');
|
||||
|
||||
return strtotime($date->datetime);
|
||||
return strtotime($date->content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the rating from a given article
|
||||
*/
|
||||
private function extract_article_rating($article){
|
||||
private function extractArticleRating($article){
|
||||
$rating = $article->find('span.rating', 0);
|
||||
if($rating === false)
|
||||
if(is_null($rating))
|
||||
returnServerError('Cannot find article rating!');
|
||||
|
||||
return $rating->getAttribute('aria-label');
|
||||
@@ -160,9 +178,9 @@ class KununuBridge extends BridgeAbstract {
|
||||
/**
|
||||
* Returns the summary from a given article
|
||||
*/
|
||||
private function extract_article_summary($article){
|
||||
$summary = $article->find('[itemprop=summary]', 0);
|
||||
if($summary === false)
|
||||
private function extractArticleSummary($article){
|
||||
$summary = $article->find('[itemprop=name]', 0);
|
||||
if(is_null($summary))
|
||||
returnServerError('Cannot find article summary!');
|
||||
|
||||
return strip_tags($summary->innertext);
|
||||
@@ -171,33 +189,28 @@ class KununuBridge extends BridgeAbstract {
|
||||
/**
|
||||
* Returns the URI from a given article
|
||||
*/
|
||||
private function extract_article_uri($article){
|
||||
// Notice: This first part is the same as in extract_article_summary!
|
||||
$summary = $article->find('[itemprop=summary]', 0);
|
||||
if($summary === false)
|
||||
returnServerError('Cannot find article summary!');
|
||||
|
||||
$anchor = $summary->find('a', 0);
|
||||
if($anchor === false)
|
||||
private function extractArticleUri($article){
|
||||
$anchor = $article->find('ku-company-review-more', 0);
|
||||
if(is_null($anchor))
|
||||
returnServerError('Cannot find article URI!');
|
||||
|
||||
return self::URI . $anchor->href;
|
||||
return self::URI . $anchor->{'review-url'};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the position of the author from a given article
|
||||
*/
|
||||
private function extract_article_author_position($article){
|
||||
// We need to parse the aside manually
|
||||
$aside = $article->find('aside', 0);
|
||||
if($aside === false)
|
||||
returnServerError('Cannot find article author information!');
|
||||
private function extractArticleAuthorPosition($article){
|
||||
// We need to parse the user-content manually
|
||||
$user_content = $article->find('div.user-content', 0);
|
||||
if(is_null($user_content))
|
||||
returnServerError('Cannot find user content!');
|
||||
|
||||
// Go through all h2 elements to find index of required span (I know... it's stupid)
|
||||
$author_position = 'Unknown';
|
||||
foreach($aside->find('h2') as $subject){
|
||||
if(stristr(strtolower($subject->plaintext), 'position')){ /* This works for at, ch, de, us */
|
||||
$author_position = $subject->next_sibling()->plaintext;
|
||||
foreach($user_content->find('div') as $content) {
|
||||
if(stristr(strtolower($content->plaintext), 'position')) { /* This works for at, ch, de, us */
|
||||
$author_position = $content->next_sibling()->plaintext;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -208,18 +221,18 @@ class KununuBridge extends BridgeAbstract {
|
||||
/**
|
||||
* Returns the description from a given article
|
||||
*/
|
||||
private function extract_article_description($article){
|
||||
$description = $article->find('div[itemprop=description]', 0);
|
||||
if($description === false)
|
||||
private function extractArticleDescription($article){
|
||||
$description = $article->find('[itemprop=reviewBody]', 0);
|
||||
if(is_null($description))
|
||||
returnServerError('Cannot find article description!');
|
||||
|
||||
return $this->fix_url($description->innertext);
|
||||
return $this->fixUrl($description->innertext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the full description from a given uri
|
||||
*/
|
||||
private function extract_full_description($uri){
|
||||
private function extractFullDescription($uri){
|
||||
// Load full article
|
||||
$html = getSimpleHTMLDOMCached($uri);
|
||||
if($html === false)
|
||||
@@ -227,10 +240,10 @@ class KununuBridge extends BridgeAbstract {
|
||||
|
||||
// Find the article
|
||||
$article = $html->find('article', 0);
|
||||
if($article === false)
|
||||
if(is_null($article))
|
||||
returnServerError('Cannot find article!');
|
||||
|
||||
// Luckily they use the same layout for the review overview and full article pages :)
|
||||
return $this->extract_article_description($article);
|
||||
return $this->extractArticleDescription($article);
|
||||
}
|
||||
}
|
||||
|
@@ -6,6 +6,8 @@ class LWNprevBridge extends BridgeAbstract{
|
||||
const CACHE_TIMEOUT = 604800; // 1 week
|
||||
const DESCRIPTION = 'LWN Free Weekly Edition available one week late';
|
||||
|
||||
private $editionTimeStamp;
|
||||
|
||||
function getURI(){
|
||||
return self::URI.'free/bigpage';
|
||||
}
|
||||
@@ -36,99 +38,64 @@ class LWNprevBridge extends BridgeAbstract{
|
||||
$content = getContents($this->getURI())
|
||||
or returnServerError('No results for LWNprev');
|
||||
|
||||
$contents = explode('<b>Page editor</b>', $content);
|
||||
|
||||
foreach($contents as $content) {
|
||||
if(strpos($content, '<html>') === false) {
|
||||
$content = <<<EOD
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html><head><title>LWN</title></head><body>{$content}</body></html>
|
||||
EOD;
|
||||
} else {
|
||||
$content = $content.'</body></html>';
|
||||
}
|
||||
|
||||
libxml_use_internal_errors(true);
|
||||
$html = new DOMDocument();
|
||||
$html->loadHTML($content);
|
||||
libxml_clear_errors();
|
||||
|
||||
$cat1='';
|
||||
$cat2='';
|
||||
|
||||
foreach($html->getElementsByTagName('a') as $a){
|
||||
if($a->textContent==='Multi-page format'){
|
||||
break;
|
||||
}
|
||||
}
|
||||
$realURI=self::URI.$a->getAttribute('href');
|
||||
$URICounter=0;
|
||||
|
||||
$edition=$html->getElementsByTagName('h1')->item(0)->textContent;
|
||||
$editionTimeStamp=strtotime(
|
||||
substr($edition,strpos($edition,'for ')+strlen('for '))
|
||||
$edition = $html->getElementsByTagName('h1');
|
||||
if($edition->length !== 0) {
|
||||
$text = $edition->item(0)->textContent;
|
||||
$this->editionTimeStamp = strtotime(
|
||||
substr($text, strpos($text, 'for ') + strlen('for '))
|
||||
);
|
||||
|
||||
foreach($html->getElementsByTagName('h2') as $h2){
|
||||
if($h2->getAttribute('class')!=='SummaryHL'){
|
||||
continue;
|
||||
}
|
||||
|
||||
$item = array();
|
||||
|
||||
$h2NextSibling=$h2->nextSibling;
|
||||
$this->jumpToNextTag($h2NextSibling);
|
||||
|
||||
switch($h2NextSibling->getAttribute('class')){
|
||||
case 'FeatureByline':
|
||||
$item['author']=$h2NextSibling->getElementsByTagName('b')->item(0)->textContent;
|
||||
break;
|
||||
case 'GAByline':
|
||||
$text=$h2NextSibling->textContent;
|
||||
$item['author']=substr($text,strpos($text,'by '));
|
||||
break;
|
||||
default:
|
||||
$item['author']='LWN';
|
||||
break;
|
||||
};
|
||||
|
||||
$h2FirstChild=$h2->firstChild;
|
||||
$this->jumpToNextTag($h2FirstChild);
|
||||
if($h2FirstChild->nodeName==='a'){
|
||||
$item['uri']=self::URI.$h2FirstChild->getAttribute('href');
|
||||
if(strpos($content, 'Cat1HL') === false) {
|
||||
$items = $this->getFeatureContents($html);
|
||||
} elseif(strpos($content, 'Cat3HL') === false) {
|
||||
$items = $this->getBriefItems($html);
|
||||
} else {
|
||||
$item['uri']=$realURI.'#'.$URICounter;
|
||||
$items = $this->getAnnouncements($html);
|
||||
}
|
||||
$URICounter++;
|
||||
|
||||
$item['timestamp']=$editionTimeStamp+$URICounter;
|
||||
|
||||
$h2PrevSibling=$h2->previousSibling;
|
||||
$this->jumpToPreviousTag($h2PrevSibling);
|
||||
switch($h2PrevSibling->getAttribute('class')){
|
||||
case 'Cat2HL':
|
||||
$cat2=$h2PrevSibling->textContent;
|
||||
$h2PrevSibling=$h2PrevSibling->previousSibling;
|
||||
$this->jumpToPreviousTag($h2PrevSibling);
|
||||
if($h2PrevSibling->getAttribute('class')!=='Cat1HL'){
|
||||
break;
|
||||
$this->items = array_merge($this->items, $items);
|
||||
}
|
||||
$cat1=$h2PrevSibling->textContent;
|
||||
break;
|
||||
case 'Cat1HL':
|
||||
$cat1=$h2PrevSibling->textContent;
|
||||
$cat2='';
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
$h2PrevSibling=null;
|
||||
|
||||
$item['title']='';
|
||||
if(!empty($cat1)){
|
||||
$item['title'].='['.$cat1.($cat2?'/'.$cat2:'').'] ';
|
||||
private function getArticleContent(&$title){
|
||||
$link = $title->firstChild;
|
||||
$this->jumpToNextTag($link);
|
||||
$item['uri'] = self::URI;
|
||||
if($link->nodeName === 'a') {
|
||||
$item['uri'] .= $link->getAttribute('href');
|
||||
}
|
||||
$item['title'].=$h2->textContent;
|
||||
|
||||
$node=$h2;
|
||||
$item['timestamp'] = $this->editionTimeStamp;
|
||||
|
||||
$node = $title;
|
||||
$content = '';
|
||||
$contentEnd = false;
|
||||
while(!$contentEnd) {
|
||||
$node = $node->nextSibling;
|
||||
if(
|
||||
!$node || (
|
||||
$node->nodeType!==XML_TEXT_NODE && (
|
||||
$node->nodeName==='h2' ||
|
||||
(!is_null($node->attributes) && !is_null($class=$node->attributes->getNamedItem('class')) &&
|
||||
in_array($class->nodeValue,array('Cat1HL','Cat2HL')))
|
||||
if(!$node || (
|
||||
$node->nodeType !== XML_TEXT_NODE &&
|
||||
$node->nodeName === 'h2' || (
|
||||
!is_null($node->attributes) &&
|
||||
!is_null($class = $node->attributes->getNamedItem('class')) &&
|
||||
in_array($class->nodeValue, array('Cat1HL','Cat2HL'))
|
||||
)
|
||||
)
|
||||
) {
|
||||
@@ -138,7 +105,161 @@ class LWNprevBridge extends BridgeAbstract{
|
||||
}
|
||||
}
|
||||
$item['content'] = $content;
|
||||
$this->items[]=$item;
|
||||
return $item;
|
||||
}
|
||||
|
||||
private function getFeatureContents(&$html){
|
||||
$items = array();
|
||||
foreach($html->getElementsByTagName('h2') as $title) {
|
||||
if($title->getAttribute('class') !== 'SummaryHL') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$item = array();
|
||||
|
||||
$author = $title->nextSibling;
|
||||
$this->jumpToNextTag($author);
|
||||
if($author->getAttribute('class') === 'FeatureByline') {
|
||||
$item['author'] = $author->getElementsByTagName('b')->item(0)->textContent;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
$item['title'] = $title->textContent;
|
||||
|
||||
$items[] = array_merge($item, $this->getArticleContent($title));
|
||||
}
|
||||
return $items;
|
||||
}
|
||||
|
||||
private function getItemPrefix(&$cat, &$cats){
|
||||
$cat1 = '';
|
||||
$cat2 = '';
|
||||
$cat3 = '';
|
||||
switch($cat->getAttribute('class')) {
|
||||
case 'Cat3HL':
|
||||
$cat3 = $cat->textContent;
|
||||
$cat = $cat->previousSibling;
|
||||
$this->jumpToPreviousTag($cat);
|
||||
$cats[2] = $cat3;
|
||||
if($cat->getAttribute('class') !== 'Cat2HL') {
|
||||
break;
|
||||
}
|
||||
case 'Cat2HL':
|
||||
$cat2 = $cat->textContent;
|
||||
$cat = $cat->previousSibling;
|
||||
$this->jumpToPreviousTag($cat);
|
||||
$cats[1] = $cat2;
|
||||
if(empty($cat3)) {
|
||||
$cats[2] = '';
|
||||
}
|
||||
if($cat->getAttribute('class') !== 'Cat1HL') {
|
||||
break;
|
||||
}
|
||||
case 'Cat1HL':
|
||||
$cat1 = $cat->textContent;
|
||||
$cats[0] = $cat1;
|
||||
if(empty($cat3)) {
|
||||
$cats[2] = '';
|
||||
}
|
||||
if(empty($cat2)) {
|
||||
$cats[1] = '';
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
$prefix = '';
|
||||
if(!empty($cats[0])) {
|
||||
$prefix .= '['.$cats[0].($cats[1] ? '/'.$cats[1] : '').'] ';
|
||||
}
|
||||
return $prefix;
|
||||
}
|
||||
|
||||
private function getAnnouncements(&$html){
|
||||
$items = array();
|
||||
$cats = array('','','');
|
||||
|
||||
foreach($html->getElementsByTagName('p') as $newsletters) {
|
||||
if($newsletters->getAttribute('class') !== 'Cat3HL') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$item = array();
|
||||
|
||||
$item['uri'] = self::URI.'#'.count($items);
|
||||
|
||||
$item['timestamp'] = $this->editionTimeStamp;
|
||||
|
||||
$item['author'] = 'LWN';
|
||||
|
||||
$cat = $newsletters->previousSibling;
|
||||
$this->jumpToPreviousTag($cat);
|
||||
$prefix = $this->getItemPrefix($cat, $cats);
|
||||
$item['title'] = $prefix.' '.$newsletters->textContent;
|
||||
|
||||
$node = $newsletters;
|
||||
$content = '';
|
||||
$contentEnd = false;
|
||||
while(!$contentEnd) {
|
||||
$node = $node->nextSibling;
|
||||
if(!$node || (
|
||||
$node->nodeType !== XML_TEXT_NODE && (
|
||||
!is_null($node->attributes) &&
|
||||
!is_null($class = $node->attributes->getNamedItem('class')) &&
|
||||
in_array($class->nodeValue, array('Cat1HL','Cat2HL','Cat3HL'))
|
||||
)
|
||||
)
|
||||
) {
|
||||
$contentEnd = true;
|
||||
} else {
|
||||
$content .= $node->C14N();
|
||||
}
|
||||
}
|
||||
$item['content'] = $content;
|
||||
$items[] = $item;
|
||||
}
|
||||
|
||||
foreach($html->getElementsByTagName('h2') as $title) {
|
||||
if($title->getAttribute('class') !== 'SummaryHL') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$item = array();
|
||||
|
||||
$cat = $title->previousSibling;
|
||||
$this->jumpToPreviousTag($cat);
|
||||
$cat = $cat->previousSibling;
|
||||
$this->jumpToPreviousTag($cat);
|
||||
$prefix = $this->getItemPrefix($cat, $cats);
|
||||
$item['title'] = $prefix.' '.$title->textContent;
|
||||
$items[] = array_merge($item, $this->getArticleContent($title));
|
||||
}
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
private function getBriefItems(&$html){
|
||||
$items = array();
|
||||
$cats = array('','','');
|
||||
foreach($html->getElementsByTagName('h2') as $title) {
|
||||
if($title->getAttribute('class') !== 'SummaryHL') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$item = array();
|
||||
|
||||
$cat = $title->previousSibling;
|
||||
$this->jumpToPreviousTag($cat);
|
||||
$cat = $cat->previousSibling;
|
||||
$this->jumpToPreviousTag($cat);
|
||||
$prefix = $this->getItemPrefix($cat, $cats);
|
||||
$item['title'] = $prefix.' '.$title->textContent;
|
||||
$items[] = array_merge($item, $this->getArticleContent($title));
|
||||
}
|
||||
|
||||
return $items;
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
30
bridges/LeBonCoinBridge.php
Executable file → Normal file
30
bridges/LeBonCoinBridge.php
Executable file → Normal file
@@ -1,12 +1,14 @@
|
||||
<?php
|
||||
class LeBonCoinBridge extends BridgeAbstract {
|
||||
|
||||
const MAINTAINER = "16mhz";
|
||||
const NAME = "LeBonCoin";
|
||||
const URI = "http://www.leboncoin.fr/";
|
||||
const DESCRIPTION = "Returns most recent results from LeBonCoin for a region, and optionally a category and a keyword .";
|
||||
const MAINTAINER = '16mhz';
|
||||
const NAME = 'LeBonCoin';
|
||||
const URI = 'https://www.leboncoin.fr/';
|
||||
const DESCRIPTION = 'Returns most recent results from LeBonCoin for a
|
||||
region, and optionally a category and a keyword .';
|
||||
|
||||
const PARAMETERS = array( array(
|
||||
const PARAMETERS = array(
|
||||
array(
|
||||
'k' => array('name' => 'Mot Clé'),
|
||||
'r' => array(
|
||||
'name' => 'Région',
|
||||
@@ -143,14 +145,16 @@ class LeBonCoinBridge extends BridgeAbstract{
|
||||
$category = 'annonces';
|
||||
}
|
||||
|
||||
$html = getSimpleHTMLDOM(
|
||||
self::URI.$category.'/offres/' . $this->getInput('r') . '/?'
|
||||
.'f=a&th=1&'
|
||||
.'q=' . urlencode($this->getInput('k'))
|
||||
) or returnServerError('Could not request LeBonCoin.');
|
||||
$html = getSimpleHTMLDOM(self::URI
|
||||
. $category
|
||||
. '/offres/'
|
||||
. $this->getInput('r')
|
||||
. '/?f=a&th=1&q='
|
||||
. urlencode($this->getInput('k')))
|
||||
or returnServerError('Could not request LeBonCoin.');
|
||||
|
||||
$list = $html->find('.tabsContent', 0);
|
||||
if($list === NULL) {
|
||||
if($list === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -165,7 +169,7 @@ class LeBonCoinBridge extends BridgeAbstract{
|
||||
$title = html_entity_decode($element->getAttribute('title'));
|
||||
$content_image = $element->find('div.item_image', 0)->find('.lazyload', 0);
|
||||
|
||||
if($content_image !== NULL) {
|
||||
if($content_image !== null) {
|
||||
$content = '<img src="' . $content_image->getAttribute('data-imgsrc') . '" alt="thumbnail">';
|
||||
} else {
|
||||
$content = "";
|
||||
@@ -176,7 +180,7 @@ class LeBonCoinBridge extends BridgeAbstract{
|
||||
|
||||
for($i = 0; $i <= 1; $i++) $content .= $detailsList->find('p.item_supp', $i)->plaintext;
|
||||
$price = $detailsList->find('h3.item_price', 0);
|
||||
$content .= $price === NULL ? '' : $price->plaintext;
|
||||
$content .= $price === null ? '' : $price->plaintext;
|
||||
|
||||
$item['title'] = $title;
|
||||
$item['content'] = $content . $date;
|
||||
|
@@ -1,11 +1,11 @@
|
||||
<?php
|
||||
class LeMondeInformatiqueBridge extends FeedExpander {
|
||||
|
||||
const MAINTAINER = "ORelio";
|
||||
const NAME = "Le Monde Informatique";
|
||||
const URI = "http://www.lemondeinformatique.fr/";
|
||||
const MAINTAINER = 'ORelio';
|
||||
const NAME = 'Le Monde Informatique';
|
||||
const URI = 'http://www.lemondeinformatique.fr/';
|
||||
const CACHE_TIMEOUT = 1800; // 30min
|
||||
const DESCRIPTION = "Returns the newest articles.";
|
||||
const DESCRIPTION = 'Returns the newest articles.';
|
||||
|
||||
public function collectData(){
|
||||
$this->collectExpandableDatas(self::URI . 'rss/rss.xml', 10);
|
||||
@@ -15,28 +15,30 @@ class LeMondeInformatiqueBridge extends FeedExpander {
|
||||
$item = parent::parseItem($newsItem);
|
||||
$article_html = getSimpleHTMLDOMCached($item['uri'])
|
||||
or returnServerError('Could not request LeMondeInformatique: ' . $item['uri']);
|
||||
$item['content'] = $this->CleanArticle($article_html->find('div#article', 0)->innertext);
|
||||
$item['content'] = $this->cleanArticle($article_html->find('div#article', 0)->innertext);
|
||||
$item['title'] = $article_html->find('h1.cleanprint-title', 0)->plaintext;
|
||||
return $item;
|
||||
}
|
||||
|
||||
function StripCDATA($string) {
|
||||
private function stripCDATA($string){
|
||||
$string = str_replace('<![CDATA[', '', $string);
|
||||
$string = str_replace(']]>', '', $string);
|
||||
return $string;
|
||||
}
|
||||
|
||||
function StripWithDelimiters($string, $start, $end) {
|
||||
private function stripWithDelimiters($string, $start, $end){
|
||||
while(strpos($string, $start) !== false) {
|
||||
$section_to_remove = substr($string, strpos($string, $start));
|
||||
$section_to_remove = substr($section_to_remove, 0, strpos($section_to_remove, $end) + strlen($end));
|
||||
$string = str_replace($section_to_remove, '', $string);
|
||||
} return $string;
|
||||
}
|
||||
|
||||
function CleanArticle($article_html) {
|
||||
$article_html = $this->StripWithDelimiters($article_html, '<script', '</script>');
|
||||
$article_html = $this->StripWithDelimiters($article_html, '<h1 class="cleanprint-title"', '</h1>');
|
||||
return $string;
|
||||
}
|
||||
|
||||
private function cleanArticle($article_html){
|
||||
$article_html = $this->stripWithDelimiters($article_html, '<script', '</script>');
|
||||
$article_html = $this->stripWithDelimiters($article_html, '<h1 class="cleanprint-title"', '</h1>');
|
||||
return $article_html;
|
||||
}
|
||||
}
|
||||
|
@@ -42,10 +42,10 @@ class LegifranceJOBridge extends BridgeAbstract{
|
||||
$html = getSimpleHTMLDOM(self::URI)
|
||||
or $this->returnServer('Unable to download ' . self::URI);
|
||||
|
||||
$this->author=trim($html->find('h2.title',0)->plaintext);
|
||||
$this->author = trim($html->find('h2.titleJO', 0)->plaintext);
|
||||
$uri = $html->find('h2.titleELI', 0)->plaintext;
|
||||
$this->uri = trim(substr($uri, strpos($uri, 'https')));
|
||||
$this->timestamp=strtotime(substr($this->uri,strpos($this->uri,'eli/jo/')+strlen('eli/jo/')));
|
||||
$this->timestamp = strtotime(substr($this->uri, strpos($this->uri, 'eli/jo/') + strlen('eli/jo/'), -5));
|
||||
|
||||
foreach($html->find('h3') as $section) {
|
||||
$subsections = $section->nextSibling()->find('h4');
|
||||
@@ -66,5 +66,3 @@ class LegifranceJOBridge extends BridgeAbstract{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@@ -1,11 +1,11 @@
|
||||
<?php
|
||||
class LesJoiesDuCodeBridge extends BridgeAbstract {
|
||||
|
||||
const MAINTAINER = "superbaillot.net";
|
||||
const NAME = "Les Joies Du Code";
|
||||
const URI = "http://lesjoiesducode.fr/";
|
||||
const MAINTAINER = 'superbaillot.net';
|
||||
const NAME = 'Les Joies Du Code';
|
||||
const URI = 'http://lesjoiesducode.fr/';
|
||||
const CACHE_TIMEOUT = 7200; // 2h
|
||||
const DESCRIPTION = "LesJoiesDuCode";
|
||||
const DESCRIPTION = 'LesJoiesDuCode';
|
||||
|
||||
public function collectData(){
|
||||
$html = getSimpleHTMLDOM(self::URI)
|
||||
@@ -30,13 +30,11 @@ class LesJoiesDuCodeBridge extends BridgeAbstract{
|
||||
$auteur = $temp->find('i', 0);
|
||||
$pos = strpos($auteur->innertext, "by");
|
||||
|
||||
if($pos > 0)
|
||||
{
|
||||
if($pos > 0) {
|
||||
$auteur = trim(str_replace("*/", "", substr($auteur->innertext, ($pos + 2))));
|
||||
$item['author'] = $auteur;
|
||||
}
|
||||
|
||||
|
||||
$item['content'] .= trim($content);
|
||||
$item['uri'] = $url;
|
||||
$item['title'] = trim($titre);
|
||||
|
@@ -12,11 +12,11 @@ class LichessBridge extends FeedExpander {
|
||||
|
||||
protected function parseItem($newsItem){
|
||||
$item = parent::parseItem($newsItem);
|
||||
$item['content'] = $this->retrieve_lichess_post($item['uri']);
|
||||
$item['content'] = $this->retrieveLichessPost($item['uri']);
|
||||
return $item;
|
||||
}
|
||||
|
||||
private function retrieve_lichess_post($blog_post_uri){
|
||||
private function retrieveLichessPost($blog_post_uri){
|
||||
$blog_post_html = getSimpleHTMLDOMCached($blog_post_uri);
|
||||
$blog_post_div = $blog_post_html->find('#lichess_blog', 0);
|
||||
|
||||
|
@@ -1,11 +1,12 @@
|
||||
<?php
|
||||
class LinkedInCompanyBridge extends BridgeAbstract {
|
||||
|
||||
const MAINTAINER = "regisenguehard";
|
||||
const NAME = "LinkedIn Company";
|
||||
const URI = "https://www.linkedin.com/";
|
||||
const MAINTAINER = 'regisenguehard';
|
||||
const NAME = 'LinkedIn Company';
|
||||
const URI = 'https://www.linkedin.com/';
|
||||
const CACHE_TIMEOUT = 21600; //6
|
||||
const DESCRIPTION = "Returns most recent actus from Company on LinkedIn. (https://www.linkedin.com/company/<strong style=\"font-weight:bold;\">apple</strong>)";
|
||||
const DESCRIPTION = 'Returns most recent actus from Company on LinkedIn.
|
||||
(https://www.linkedin.com/company/<strong style=\"font-weight:bold;\">apple</strong>)';
|
||||
|
||||
const PARAMETERS = array( array(
|
||||
'c' => array(
|
||||
|
@@ -3,9 +3,9 @@ require_once('MoebooruBridge.php');
|
||||
|
||||
class LolibooruBridge extends MoebooruBridge {
|
||||
|
||||
const MAINTAINER = "mitsukarenai";
|
||||
const NAME = "Lolibooru";
|
||||
const URI = "https://lolibooru.moe/";
|
||||
const DESCRIPTION = "Returns images from given page and tags";
|
||||
const MAINTAINER = 'mitsukarenai';
|
||||
const NAME = 'Lolibooru';
|
||||
const URI = 'https://lolibooru.moe/';
|
||||
const DESCRIPTION = 'Returns images from given page and tags';
|
||||
|
||||
}
|
||||
|
@@ -1,11 +1,11 @@
|
||||
<?php
|
||||
class MangareaderBridge extends BridgeAbstract {
|
||||
|
||||
const MAINTAINER = "logmanoriginal";
|
||||
const NAME = "Mangareader Bridge";
|
||||
const URI = "http://www.mangareader.net/";
|
||||
const MAINTAINER = 'logmanoriginal';
|
||||
const NAME = 'Mangareader Bridge';
|
||||
const URI = 'http://www.mangareader.net';
|
||||
const CACHE_TIMEOUT = 10800; // 3h
|
||||
const DESCRIPTION = "Returns the latest updates, popular mangas or manga updates (new chapters)";
|
||||
const DESCRIPTION = 'Returns the latest updates, popular mangas or manga updates (new chapters)';
|
||||
|
||||
const PARAMETERS = array(
|
||||
'Get latest updates' => array(),
|
||||
@@ -95,13 +95,13 @@ class MangareaderBridge extends BridgeAbstract {
|
||||
switch($this->queriedContext) {
|
||||
case 'Get latest updates':
|
||||
$this->request = 'Latest updates';
|
||||
$this->get_latest_updates($xpath);
|
||||
$this->getLatestUpdates($xpath);
|
||||
break;
|
||||
case 'Get popular mangas':
|
||||
// Find manga name within "Popular mangas for ..."
|
||||
$pagetitle = $xpath->query(".//*[@id='bodyalt']/h1")->item(0)->nodeValue;
|
||||
$this->request = substr($pagetitle, 0, strrpos($pagetitle, " -"));
|
||||
$this->get_popular_mangas($xpath);
|
||||
$this->getPopularMangas($xpath);
|
||||
break;
|
||||
case 'Get manga updates':
|
||||
$limit = $this->getInput('limit');
|
||||
@@ -113,7 +113,7 @@ class MangareaderBridge extends BridgeAbstract {
|
||||
->item(0)
|
||||
->nodeValue;
|
||||
|
||||
$this->get_manga_updates($xpath, $limit);
|
||||
$this->getMangaUpdates($xpath, $limit);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -126,7 +126,7 @@ class MangareaderBridge extends BridgeAbstract {
|
||||
}
|
||||
}
|
||||
|
||||
private function get_latest_updates($xpath){
|
||||
private function getLatestUpdates($xpath){
|
||||
// Query each item (consists of Manga + chapters)
|
||||
$nodes = $xpath->query("//*[@id='latestchapters']/table//td");
|
||||
|
||||
@@ -149,8 +149,7 @@ class MangareaderBridge extends BridgeAbstract {
|
||||
if($item['content'] <> "") {
|
||||
$item['content'] .= "<br>";
|
||||
}
|
||||
$item['content'] .=
|
||||
"<a href='"
|
||||
$item['content'] .= "<a href='"
|
||||
. self::URI
|
||||
. htmlspecialchars($chapter->getAttribute('href'))
|
||||
. "'>"
|
||||
@@ -163,7 +162,7 @@ class MangareaderBridge extends BridgeAbstract {
|
||||
}
|
||||
}
|
||||
|
||||
private function get_popular_mangas($xpath){
|
||||
private function getPopularMangas($xpath){
|
||||
// Query all mangas
|
||||
$mangas = $xpath->query("//*[@id='mangaresults']/*[@class='mangaresultitem']");
|
||||
|
||||
@@ -201,7 +200,7 @@ EOD;
|
||||
}
|
||||
}
|
||||
|
||||
private function get_manga_updates($xpath, $limit){
|
||||
private function getMangaUpdates($xpath, $limit){
|
||||
$query = "(.//*[@id='listing']//tr)[position() > 1]";
|
||||
|
||||
if($limit !== -1) {
|
||||
@@ -239,13 +238,12 @@ EOD;
|
||||
case 'Get manga updates':
|
||||
$path = $this->getInput('path');
|
||||
break;
|
||||
default: return parent::getURI();
|
||||
}
|
||||
return self::URI . $path;
|
||||
return self::URI . '/' . $path;
|
||||
}
|
||||
|
||||
|
||||
public function getName(){
|
||||
return (!empty($this->request) ? $this->request . ' - ' : '') . 'Mangareader Bridge';
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
@@ -3,9 +3,9 @@ require_once('Shimmie2Bridge.php');
|
||||
|
||||
class MilbooruBridge extends Shimmie2Bridge {
|
||||
|
||||
const MAINTAINER = "mitsukarenai";
|
||||
const NAME = "Milbooru";
|
||||
const URI = "http://sheslostcontrol.net/moe/shimmie/";
|
||||
const DESCRIPTION = "Returns images from given page";
|
||||
const MAINTAINER = 'mitsukarenai';
|
||||
const NAME = 'Milbooru';
|
||||
const URI = 'http://sheslostcontrol.net/moe/shimmie/';
|
||||
const DESCRIPTION = 'Returns images from given page';
|
||||
|
||||
}
|
||||
|
53
bridges/MixCloudBridge.php
Normal file
53
bridges/MixCloudBridge.php
Normal file
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
class MixCloudBridge extends BridgeAbstract {
|
||||
|
||||
const MAINTAINER = 'Alexis CHEMEL';
|
||||
const NAME = 'MixCloud';
|
||||
const URI = 'https://www.mixcloud.com';
|
||||
const CACHE_TIMEOUT = 3600; // 1h
|
||||
const DESCRIPTION = 'Returns latest musics on user stream';
|
||||
|
||||
const PARAMETERS = array(array(
|
||||
'u' => array(
|
||||
'name' => 'username',
|
||||
'required' => true,
|
||||
)
|
||||
));
|
||||
|
||||
public function getName(){
|
||||
if(!is_null($this->getInput('u'))) {
|
||||
return 'MixCloud - ' . $this->getInput('u');
|
||||
}
|
||||
|
||||
return parent::getName();
|
||||
}
|
||||
|
||||
public function collectData(){
|
||||
ini_set('user_agent', 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:53.0) Gecko/20100101 Firefox/53.0');
|
||||
|
||||
$html = getSimpleHTMLDOM(self::URI . '/' . $this->getInput('u'))
|
||||
or returnServerError('Could not request MixCloud.');
|
||||
|
||||
foreach($html->find('section.card') as $element) {
|
||||
|
||||
$item = array();
|
||||
|
||||
$item['uri'] = self::URI . $element->find('hgroup.card-title h1 a', 0)->getAttribute('href');
|
||||
$item['title'] = html_entity_decode(
|
||||
$element->find('hgroup.card-title h1 a span', 0)->getAttribute('title'),
|
||||
ENT_QUOTES
|
||||
);
|
||||
|
||||
$image = $element->find('a.album-art img', 0);
|
||||
|
||||
if($image) {
|
||||
$item['content'] = '<img src="' . $image->getAttribute('src') . '" />';
|
||||
}
|
||||
|
||||
$item['author'] = trim($element->find('hgroup.card-title h2 a', 0)->innertext);
|
||||
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,10 +1,11 @@
|
||||
<?php
|
||||
class MoebooruBridge extends BridgeAbstract {
|
||||
|
||||
const NAME = "Moebooru";
|
||||
const URI = "https://moe.dev.myconan.net/";
|
||||
const NAME = 'Moebooru';
|
||||
const URI = 'https://moe.dev.myconan.net/';
|
||||
const CACHE_TIMEOUT = 1800; // 30min
|
||||
const DESCRIPTION = "Returns images from given page";
|
||||
const DESCRIPTION = 'Returns images from given page';
|
||||
const MAINTAINER = 'pmaziere';
|
||||
|
||||
const PARAMETERS = array( array(
|
||||
'p' => array(
|
||||
@@ -12,34 +13,43 @@ class MoebooruBridge extends BridgeAbstract{
|
||||
'defaultValue' => 1,
|
||||
'type' => 'number'
|
||||
),
|
||||
't'=>array('name'=>'tags')
|
||||
't' => array(
|
||||
'name' => 'tags'
|
||||
)
|
||||
));
|
||||
|
||||
protected function getFullURI(){
|
||||
return $this->getURI().'post?'
|
||||
.'page='.$this->getInput('p')
|
||||
.'&tags='.urlencode($this->getInput('t'));
|
||||
return $this->getURI()
|
||||
. 'post?page='
|
||||
. $this->getInput('p')
|
||||
. '&tags='
|
||||
. urlencode($this->getInput('t'));
|
||||
}
|
||||
|
||||
public function collectData(){
|
||||
$html = getSimpleHTMLDOM($this->getFullURI())
|
||||
or returnServerError('Could not request ' . $this->getName());
|
||||
|
||||
|
||||
$input_json = explode('Post.register(', $html);
|
||||
foreach($input_json as $element)
|
||||
$data[] = preg_replace('/}\)(.*)/', '}', $element);
|
||||
unset($data[0]);
|
||||
|
||||
foreach($data as $datai) {
|
||||
$json = json_decode($datai, TRUE);
|
||||
$json = json_decode($datai, true);
|
||||
$item = array();
|
||||
$item['uri'] = $this->getURI() . '/post/show/' . $json['id'];
|
||||
$item['postid'] = $json['id'];
|
||||
$item['timestamp'] = $json['created_at'];
|
||||
$item['imageUri'] = $json['file_url'];
|
||||
$item['title'] = $this->getName() . ' | ' . $json['id'];
|
||||
$item['content'] = '<a href="' . $item['imageUri'] . '"><img src="' . $json['preview_url'] . '" /></a><br>Tags: '.$json['tags'];
|
||||
$item['content'] = '<a href="'
|
||||
. $item['imageUri']
|
||||
. '"><img src="'
|
||||
. $json['preview_url']
|
||||
. '" /></a><br>Tags: '
|
||||
. $json['tags'];
|
||||
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
|
327
bridges/MoinMoinBridge.php
Normal file
327
bridges/MoinMoinBridge.php
Normal file
@@ -0,0 +1,327 @@
|
||||
<?php
|
||||
class MoinMoinBridge extends BridgeAbstract {
|
||||
|
||||
const MAINTAINER = 'logmanoriginal';
|
||||
const NAME = 'MoinMoin Bridge';
|
||||
const URI = 'https://moinmo.in';
|
||||
const DESCRIPTION = 'Generates feeds for pages of a MoinMoin (compatible) wiki';
|
||||
const PARAMETERS = array(
|
||||
array(
|
||||
'source' => array(
|
||||
'name' => 'Source',
|
||||
'type' => 'text',
|
||||
'required' => true,
|
||||
'title' => 'Insert wiki page URI (e.g.: https://moinmo.in/MoinMoin)',
|
||||
'exampleValue' => 'https://moinmo.in/MoinMoin'
|
||||
),
|
||||
'separator' => array(
|
||||
'name' => 'Separator',
|
||||
'type' => 'list',
|
||||
'requied' => true,
|
||||
'title' => 'Defines the separtor for splitting content into feeds',
|
||||
'defaultValue' => 'h2',
|
||||
'values' => array(
|
||||
'Header (h1)' => 'h1',
|
||||
'Header (h2)' => 'h2',
|
||||
'Header (h3)' => 'h3',
|
||||
'List element (li)' => 'li',
|
||||
'Anchor (a)' => 'a'
|
||||
)
|
||||
),
|
||||
'limit' => array(
|
||||
'name' => 'Limit',
|
||||
'type' => 'number',
|
||||
'required' => false,
|
||||
'title' => 'Number of items to return (from top)',
|
||||
'defaultValue' => -1
|
||||
),
|
||||
'content' => array(
|
||||
'name' => 'Content',
|
||||
'type' => 'list',
|
||||
'required' => false,
|
||||
'title' => 'Defines how feed contents are build',
|
||||
'defaultValue' => 'separator',
|
||||
'values' => array(
|
||||
'By separator' => 'separator',
|
||||
'Follow link (only for anchor)' => 'follow',
|
||||
'None' => 'none'
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
private $title = '';
|
||||
|
||||
public function collectData(){
|
||||
/* MoinMoin uses a rather unpleasent representation of HTML. Instead of
|
||||
* using tags like <article/>, <navigation/>, <header/>, etc... it uses
|
||||
* <div/>, <span/> and <p/>. Also each line is literaly identified via
|
||||
* IDs. The only way to distinguish content is via headers, though not
|
||||
* in all cases.
|
||||
*
|
||||
* Example (indented for the sake of readability):
|
||||
* ...
|
||||
* <span class="anchor" id="line-1"></span>
|
||||
* <span class="anchor" id="line-2"></span>
|
||||
* <span class="anchor" id="line-3"></span>
|
||||
* <span class="anchor" id="line-4"></span>
|
||||
* <span class="anchor" id="line-5"></span>
|
||||
* <span class="anchor" id="line-6"></span>
|
||||
* <span class="anchor" id="line-7"></span>
|
||||
* <span class="anchor" id="line-8"></span>
|
||||
* <span class="anchor" id="line-9"></span>
|
||||
* <p class="line867">MoinMoin is a Wiki software implemented in
|
||||
* <a class="interwiki" href="/Python" title="MoinMoin">Python</a>
|
||||
* and distributed as Free Software under
|
||||
* <a class="interwiki" href="/GPL" title="MoinMoin">GNU GPL license</a>.
|
||||
* ...
|
||||
*/
|
||||
$html = getSimpleHTMLDOM($this->getInput('source'))
|
||||
or returnServerError('Could not load ' . $this->getInput('source'));
|
||||
|
||||
// Some anchors link to local sites or local IDs (both don't work well
|
||||
// in feeds)
|
||||
$html = $this->fixAnchors($html);
|
||||
|
||||
$this->title = $html->find('title', 0)->innertext . ' | ' . self::NAME;
|
||||
|
||||
// Here we focus on simple author and timestamp information from the given
|
||||
// page. Later we update this information in case the anchor is followed.
|
||||
$author = $this->findAuthor($html);
|
||||
$timestamp = $this->findTimestamp($html);
|
||||
|
||||
$sections = $this->splitSections($html);
|
||||
|
||||
foreach($sections as $section) {
|
||||
$item = array();
|
||||
|
||||
$item['uri'] = $this->findSectionAnchor($section[0]);
|
||||
|
||||
switch($this->getInput('content')) {
|
||||
case 'none': // Do not return any content
|
||||
break;
|
||||
case 'follow': // Follow the anchor
|
||||
// We can only follow anchors (use default otherwise)
|
||||
if($this->getInput('separator') === 'a') {
|
||||
$content = $this->followAnchor($item['uri']);
|
||||
|
||||
// Return only actual content
|
||||
$item['content'] = $content->find('div#page', 0)->innertext;
|
||||
|
||||
// Each page could have its own author and timestamp
|
||||
$author = $this->findAuthor($content);
|
||||
$timestamp = $this->findTimestamp($content);
|
||||
|
||||
break;
|
||||
}
|
||||
case 'separator':
|
||||
default: // Use contents from the current page
|
||||
$item['content'] = $this->cleanArticle($section[2]);
|
||||
}
|
||||
|
||||
if(!is_null($author)) $item['author'] = $author;
|
||||
if(!is_null($timestamp)) $item['timestamp'] = $timestamp;
|
||||
$item['title'] = strip_tags($section[1]);
|
||||
|
||||
// Skip items with empty title
|
||||
if(empty(trim($item['title']))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->items[] = $item;
|
||||
|
||||
if($this->getInput('limit') > 0
|
||||
&& count($this->items) >= $this->getInput('limit')) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return $this->title ?: parent::getName();
|
||||
}
|
||||
|
||||
public function getURI(){
|
||||
return $this->getInput('source') ?: parent::getURI();
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits the html into sections.
|
||||
*
|
||||
* Returns an array with one element per section. Each element consists of:
|
||||
* [0] The entire section
|
||||
* [1] The section title
|
||||
* [2] The section content
|
||||
*/
|
||||
private function splitSections($html){
|
||||
$content = $html->find('div#page', 0)->innertext
|
||||
or returnServerError('Unable to find <div id="page"/>!');
|
||||
|
||||
$sections = array();
|
||||
|
||||
$regex = implode(
|
||||
'',
|
||||
array(
|
||||
"\<{$this->getInput('separator')}.+?(?=\>)\>",
|
||||
"(.+?)(?=\<\/{$this->getInput('separator')}\>)",
|
||||
"\<\/{$this->getInput('separator')}\>",
|
||||
"(.+?)((?=\<{$this->getInput('separator')})|(?=\<div\sid=\"pagebottom\")){1}"
|
||||
)
|
||||
);
|
||||
|
||||
preg_match_all(
|
||||
'/' . $regex . '/m',
|
||||
$content,
|
||||
$sections,
|
||||
PREG_SET_ORDER
|
||||
);
|
||||
|
||||
// Some pages don't use headers, return page as one feed
|
||||
if(count($sections) === 0) {
|
||||
return array(
|
||||
array(
|
||||
$content,
|
||||
$html->find('title', 0)->innertext,
|
||||
$content
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return $sections;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the anchor for a given section
|
||||
*/
|
||||
private function findSectionAnchor($section){
|
||||
$html = str_get_html($section);
|
||||
|
||||
// For IDs
|
||||
$anchor = $html->find($this->getInput('separator') . '[id=]', 0);
|
||||
if(!is_null($anchor)) {
|
||||
return $this->getInput('source') . '#' . $anchor->id;
|
||||
}
|
||||
|
||||
// For actual anchors
|
||||
$anchor = $html->find($this->getInput('separator') . '[href=]', 0);
|
||||
if(!is_null($anchor)) {
|
||||
return $anchor->href;
|
||||
}
|
||||
|
||||
// Nothing found
|
||||
return $this->getInput('source');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the author
|
||||
*
|
||||
* Notice: Some pages don't provide author information
|
||||
*/
|
||||
private function findAuthor($html){
|
||||
/* Example:
|
||||
* <p id="pageinfo" class="info" dir="ltr" lang="en">MoinMoin: LocalSpellingWords
|
||||
* (last edited 2017-02-16 15:36:31 by <span title="??? @ hosted-by.leaseweb.com
|
||||
* [178.162.199.143]">hosted-by</span>)</p>
|
||||
*/
|
||||
$pageinfo = $html->find('[id="pageinfo"]', 0);
|
||||
|
||||
if(is_null($pageinfo)) {
|
||||
return null;
|
||||
} else {
|
||||
$author = $pageinfo->find('[title=]', 0);
|
||||
if(is_null($author)) {
|
||||
return null;
|
||||
} else {
|
||||
return trim(explode('@', $author->title)[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the time of last edit
|
||||
*
|
||||
* Notice: Some pages don't provide this information
|
||||
*/
|
||||
private function findTimestamp($html){
|
||||
// See example of findAuthor()
|
||||
$pageinfo = $html->find('[id="pageinfo"]', 0);
|
||||
|
||||
if(is_null($pageinfo)) {
|
||||
return null;
|
||||
} else {
|
||||
$timestamp = $pageinfo->innertext;
|
||||
$matches = array();
|
||||
preg_match('/.+?(?=\().+?(?=\d)([0-9\-\s\:]+)/m', $pageinfo, $matches);
|
||||
return strtotime($matches[1]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the original HTML with all anchors fixed (makes relative anchors
|
||||
* absolute)
|
||||
*/
|
||||
private function fixAnchors($html, $source = null){
|
||||
|
||||
$source = $source ?: $this->getURI();
|
||||
|
||||
foreach($html->find('a') as $anchor) {
|
||||
switch(substr($anchor->href, 0, 1)) {
|
||||
case 'h': // http or https, no actions required
|
||||
break;
|
||||
case '/': // some relative path
|
||||
$anchor->href = $this->findDomain($source) . $anchor->href;
|
||||
break;
|
||||
case '#': // it's an ID
|
||||
default: // probably something like ? or &, skip empty ones
|
||||
if(!isset($anchor->href))
|
||||
break;
|
||||
$anchor->href = $source . $anchor->href;
|
||||
}
|
||||
}
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the full article of a given anchor (if the anchor is from the same
|
||||
* wiki domain)
|
||||
*/
|
||||
private function followAnchor($anchor){
|
||||
if(strrpos($anchor, $this->findDomain($this->getInput('source')) === false)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$html = getSimpleHTMLDOMCached($anchor);
|
||||
if(!$html) { // Cannot load article
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->fixAnchors($html, $anchor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the domain for a given URI
|
||||
*/
|
||||
private function findDomain($uri){
|
||||
$matches = array();
|
||||
preg_match('/(http[s]{0,1}:\/\/.+?(?=\/))/', $uri, $matches);
|
||||
return $matches[1];
|
||||
}
|
||||
|
||||
/* This function is a copy from CNETBridge */
|
||||
private function stripWithDelimiters($string, $start, $end){
|
||||
while(strpos($string, $start) !== false) {
|
||||
$section_to_remove = substr($string, strpos($string, $start));
|
||||
$section_to_remove = substr($section_to_remove, 0, strpos($section_to_remove, $end) + strlen($end));
|
||||
$string = str_replace($section_to_remove, '', $string);
|
||||
}
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
/* This function is based on CNETBridge */
|
||||
private function cleanArticle($article_html){
|
||||
$article_html = $this->stripWithDelimiters($article_html, '<script', '</script>');
|
||||
return $article_html;
|
||||
}
|
||||
}
|
@@ -1,11 +1,11 @@
|
||||
<?php
|
||||
class MondeDiploBridge extends BridgeAbstract {
|
||||
|
||||
const MAINTAINER = "Pitchoule";
|
||||
const MAINTAINER = 'Pitchoule';
|
||||
const NAME = 'Monde Diplomatique';
|
||||
const URI = 'http://www.monde-diplomatique.fr/';
|
||||
const CACHE_TIMEOUT = 21600; //6h
|
||||
const DESCRIPTION = "Returns most recent results from MondeDiplo.";
|
||||
const DESCRIPTION = 'Returns most recent results from MondeDiplo.';
|
||||
|
||||
public function collectData(){
|
||||
$html = getSimpleHTMLDOM(self::URI)
|
||||
@@ -16,7 +16,10 @@ class MondeDiploBridge extends BridgeAbstract{
|
||||
$item = array();
|
||||
$item['uri'] = self::URI . $element->href;
|
||||
$item['title'] = $element->find('h3', 0)->plaintext;
|
||||
$item['content'] = $element->find('div.dates_auteurs', 0)->plaintext . '<br>' . strstr($element->find('div', 0)->plaintext, $element->find('div.dates_auteurs', 0)->plaintext, true);
|
||||
$item['content'] = $element->find('div.dates_auteurs', 0)->plaintext
|
||||
. '<br>'
|
||||
. strstr($element->find('div', 0)->plaintext, $element->find('div.dates_auteurs', 0)->plaintext, true);
|
||||
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
|
@@ -1,30 +1,32 @@
|
||||
<?php
|
||||
class MsnMondeBridge extends BridgeAbstract {
|
||||
|
||||
const MAINTAINER = "kranack";
|
||||
const MAINTAINER = 'kranack';
|
||||
const NAME = 'MSN Actu Monde';
|
||||
const URI = 'http://www.msn.com/';
|
||||
const DESCRIPTION = "Returns the 10 newest posts from MSN Actualités (full text)";
|
||||
const DESCRIPTION = 'Returns the 10 newest posts from MSN Actualités (full text)';
|
||||
|
||||
public function getURI(){
|
||||
return self::URI . 'fr-fr/actualite/monde';
|
||||
}
|
||||
|
||||
private function MsnMondeExtractContent($url, &$item) {
|
||||
private function msnMondeExtractContent($url, &$item){
|
||||
$html2 = getSimpleHTMLDOM($url);
|
||||
$item['content'] = $html2->find('#content', 0)->find('article', 0)->find('section', 0)->plaintext;
|
||||
$item['timestamp'] = strtotime($html2->find('.authorinfo-txt', 0)->find('time', 0)->datetime);
|
||||
}
|
||||
|
||||
public function collectData(){
|
||||
$html = getSimpleHTMLDOM($this->getURI()) or returnServerError('Could not request MsnMonde.');
|
||||
$html = getSimpleHTMLDOM($this->getURI())
|
||||
or returnServerError('Could not request MsnMonde.');
|
||||
|
||||
$limit = 0;
|
||||
foreach($html->find('.smalla') as $article) {
|
||||
if($limit < 10) {
|
||||
$item = array();
|
||||
$item['title'] = utf8_decode($article->find('h4', 0)->innertext);
|
||||
$item['uri'] = self::URI . utf8_decode($article->find('a', 0)->href);
|
||||
$this->MsnMondeExtractContent($item['uri'], $item);
|
||||
$this->msnMondeExtractContent($item['uri'], $item);
|
||||
$this->items[] = $item;
|
||||
$limit++;
|
||||
}
|
||||
|
@@ -3,10 +3,10 @@ require_once('GelbooruBridge.php');
|
||||
|
||||
class MspabooruBridge extends GelbooruBridge {
|
||||
|
||||
const MAINTAINER = "mitsukarenai";
|
||||
const NAME = "Mspabooru";
|
||||
const URI = "http://mspabooru.com/";
|
||||
const DESCRIPTION = "Returns images from given page";
|
||||
|
||||
const MAINTAINER = 'mitsukarenai';
|
||||
const NAME = 'Mspabooru';
|
||||
const URI = 'http://mspabooru.com/';
|
||||
const DESCRIPTION = 'Returns images from given page';
|
||||
const PIDBYPAGE = 50;
|
||||
|
||||
}
|
||||
|
@@ -1,19 +1,20 @@
|
||||
<?php
|
||||
class NasaApodBridge extends BridgeAbstract {
|
||||
|
||||
const MAINTAINER = "corenting";
|
||||
const NAME = "NASA APOD Bridge";
|
||||
const URI = "http://apod.nasa.gov/apod/";
|
||||
const MAINTAINER = 'corenting';
|
||||
const NAME = 'NASA APOD Bridge';
|
||||
const URI = 'https://apod.nasa.gov/apod/';
|
||||
const CACHE_TIMEOUT = 43200; // 12h
|
||||
const DESCRIPTION = "Returns the 3 latest NASA APOD pictures and explanations";
|
||||
const DESCRIPTION = 'Returns the 3 latest NASA APOD pictures and explanations';
|
||||
|
||||
public function collectData(){
|
||||
|
||||
$html = getSimpleHTMLDOM(self::URI.'archivepix.html') or returnServerError('Error while downloading the website content');
|
||||
$html = getSimpleHTMLDOM(self::URI . 'archivepix.html')
|
||||
or returnServerError('Error while downloading the website content');
|
||||
|
||||
$list = explode("<br>", $html->find('b', 0)->innertext);
|
||||
|
||||
for($i = 0; $i < 3;$i++)
|
||||
{
|
||||
for($i = 0; $i < 3; $i++) {
|
||||
$line = $list[$i];
|
||||
$item = array();
|
||||
|
||||
|
@@ -1,17 +1,19 @@
|
||||
<?php
|
||||
class NeuviemeArtBridge extends FeedExpander {
|
||||
|
||||
const MAINTAINER = "ORelio";
|
||||
const MAINTAINER = 'ORelio';
|
||||
const NAME = '9ème Art Bridge';
|
||||
const URI = "http://www.9emeart.fr/";
|
||||
const DESCRIPTION = "Returns the newest articles.";
|
||||
const URI = 'http://www.9emeart.fr/';
|
||||
const DESCRIPTION = 'Returns the newest articles.';
|
||||
|
||||
private function StripWithDelimiters($string, $start, $end) {
|
||||
private function stripWithDelimiters($string, $start, $end){
|
||||
while(strpos($string, $start) !== false) {
|
||||
$section_to_remove = substr($string, strpos($string, $start));
|
||||
$section_to_remove = substr($section_to_remove, 0, strpos($section_to_remove, $end) + strlen($end));
|
||||
$string = str_replace($section_to_remove, '', $string);
|
||||
} return $string;
|
||||
}
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
protected function parseItem($item){
|
||||
@@ -39,9 +41,9 @@ class NeuviemeArtBridge extends FeedExpander {
|
||||
'src="/', 'src="' . self::URI,
|
||||
$article_html->find('div.newsGenerique_con', 0)->innertext
|
||||
);
|
||||
$article_content = $this->StripWithDelimiters($article_content, '<script', '</script>');
|
||||
$article_content = $this->StripWithDelimiters($article_content, '<style', '</style>');
|
||||
$article_content = $this->StripWithDelimiters($article_content, '<link', '>');
|
||||
$article_content = $this->stripWithDelimiters($article_content, '<script', '</script>');
|
||||
$article_content = $this->stripWithDelimiters($article_content, '<style', '</style>');
|
||||
$article_content = $this->stripWithDelimiters($article_content, '<link', '>');
|
||||
|
||||
$item['content'] = $article_content;
|
||||
|
||||
|
@@ -1,10 +1,10 @@
|
||||
<?php
|
||||
class NextInpactBridge extends FeedExpander {
|
||||
|
||||
const MAINTAINER = "qwertygc";
|
||||
const NAME = "NextInpact Bridge";
|
||||
const URI = "http://www.nextinpact.com/";
|
||||
const DESCRIPTION = "Returns the newest articles.";
|
||||
const MAINTAINER = 'qwertygc';
|
||||
const NAME = 'NextInpact Bridge';
|
||||
const URI = 'https://www.nextinpact.com/';
|
||||
const DESCRIPTION = 'Returns the newest articles.';
|
||||
|
||||
public function collectData(){
|
||||
$this->collectExpandableDatas(self::URI . 'rss/news.xml', 10);
|
||||
@@ -12,15 +12,20 @@ class NextInpactBridge extends FeedExpander {
|
||||
|
||||
protected function parseItem($newsItem){
|
||||
$item = parent::parseItem($newsItem);
|
||||
$item['content'] = $this->ExtractContent($item['uri']);
|
||||
$item['content'] = $this->extractContent($item['uri']);
|
||||
return $item;
|
||||
}
|
||||
|
||||
private function ExtractContent($url) {
|
||||
private function extractContent($url){
|
||||
$html2 = getSimpleHTMLDOMCached($url);
|
||||
$text = '<p><em>'.$html2->find('span.sub_title', 0)->innertext.'</em></p>'
|
||||
.'<p><img src="'.$html2->find('div.container_main_image_article', 0)->find('img.dedicated',0)->src.'" alt="-" /></p>'
|
||||
.'<div>'.$html2->find('div[itemprop=articleBody]', 0)->innertext.'</div>';
|
||||
$text = '<p><em>'
|
||||
. $html2->find('span.sub_title', 0)->innertext
|
||||
. '</em></p><p><img src="'
|
||||
. $html2->find('div.container_main_image_article', 0)->find('img.dedicated', 0)->src
|
||||
. '" alt="-" /></p><div>'
|
||||
. $html2->find('div[itemprop=articleBody]', 0)->innertext
|
||||
. '</div>';
|
||||
|
||||
$premium_article = $html2->find('h2.title_reserve_article', 0);
|
||||
if (is_object($premium_article))
|
||||
$text = $text . '<p><em>' . $premium_article->innertext . '</em></p>';
|
||||
|
@@ -43,28 +43,32 @@ class NextgovBridge extends FeedExpander {
|
||||
}
|
||||
}
|
||||
|
||||
$item['content'] .= $this->ExtractContent($item['uri']);
|
||||
$item['content'] .= $this->extractContent($item['uri']);
|
||||
return $item;
|
||||
}
|
||||
|
||||
private function StripWithDelimiters($string, $start, $end) {
|
||||
private function stripWithDelimiters($string, $start, $end){
|
||||
while (strpos($string, $start) !== false) {
|
||||
$section_to_remove = substr($string, strpos($string, $start));
|
||||
$section_to_remove = substr($section_to_remove, 0, strpos($section_to_remove, $end) + strlen($end));
|
||||
$string = str_replace($section_to_remove, '', $string);
|
||||
} return $string;
|
||||
}
|
||||
|
||||
private function ExtractContent($url){
|
||||
return $string;
|
||||
}
|
||||
|
||||
private function extractContent($url){
|
||||
$article = getSimpleHTMLDOMCached($url)
|
||||
or returnServerError('Could not request Nextgov: ' . $url);
|
||||
|
||||
$contents = $article->find('div.wysiwyg', 0)->innertext;
|
||||
$contents = $this->StripWithDelimiters($contents, '<div class="ad-container">', '</div>');
|
||||
$contents = $this->StripWithDelimiters($contents, '<div', '</div>'); //ad outer div
|
||||
return $this->StripWithDelimiters($contents, '<script', '</script>');
|
||||
$contents = $this->stripWithDelimiters($contents, '<div class="ad-container">', '</div>');
|
||||
$contents = $this->stripWithDelimiters($contents, '<div', '</div>'); //ad outer div
|
||||
return $this->stripWithDelimiters($contents, '<script', '</script>');
|
||||
$contents = ($article_thumbnail == '' ? '' : '<p><img src="' . $article_thumbnail . '" /></p>')
|
||||
.'<p><b>'.$article_subtitle.'</b></p>'
|
||||
. '<p><b>'
|
||||
. $article_subtitle
|
||||
. '</b></p>'
|
||||
. trim($contents);
|
||||
}
|
||||
}
|
||||
|
@@ -1,10 +1,10 @@
|
||||
<?php
|
||||
class NiceMatinBridge extends FeedExpander {
|
||||
|
||||
const MAINTAINER = "pit-fgfjiudghdf";
|
||||
const NAME = "NiceMatin";
|
||||
const URI = "http://www.nicematin.com/";
|
||||
const DESCRIPTION = "Returns the 10 newest posts from NiceMatin (full text)";
|
||||
const MAINTAINER = 'pit-fgfjiudghdf';
|
||||
const NAME = 'NiceMatin';
|
||||
const URI = 'http://www.nicematin.com/';
|
||||
const DESCRIPTION = 'Returns the 10 newest posts from NiceMatin (full text)';
|
||||
|
||||
public function collectData(){
|
||||
$this->collectExpandableDatas(self::URI . 'derniere-minute/rss', 10);
|
||||
@@ -12,11 +12,11 @@ class NiceMatinBridge extends FeedExpander {
|
||||
|
||||
protected function parseItem($newsItem){
|
||||
$item = parent::parseItem($newsItem);
|
||||
$item['content'] = $this->NiceMatinExtractContent($item['uri']);
|
||||
$item['content'] = $this->extractContent($item['uri']);
|
||||
return $item;
|
||||
}
|
||||
|
||||
private function NiceMatinExtractContent($url) {
|
||||
private function extractContent($url){
|
||||
$html = getSimpleHTMLDOMCached($url);
|
||||
if(!$html)
|
||||
return 'Could not acquire content from url: ' . $url . '!';
|
||||
|
@@ -1,11 +1,11 @@
|
||||
<?php
|
||||
class NovelUpdatesBridge extends BridgeAbstract {
|
||||
|
||||
const MAINTAINER = "albirew";
|
||||
const NAME = "Novel Updates";
|
||||
const URI = "http://www.novelupdates.com/";
|
||||
const MAINTAINER = 'albirew';
|
||||
const NAME = 'Novel Updates';
|
||||
const URI = 'http://www.novelupdates.com/';
|
||||
const CACHE_TIMEOUT = 21600; // 6h
|
||||
const DESCRIPTION = "Returns releases from Novel Updates";
|
||||
const DESCRIPTION = 'Returns releases from Novel Updates';
|
||||
const PARAMETERS = array( array(
|
||||
'n' => array(
|
||||
'name' => 'Novel name as found in the url',
|
||||
@@ -17,9 +17,13 @@ class NovelUpdatesBridge extends BridgeAbstract{
|
||||
private $seriesTitle = '';
|
||||
|
||||
public function getURI(){
|
||||
if(!is_null($this->getInput('n'))) {
|
||||
return static::URI . '/series/' . $this->getInput('n') . '/';
|
||||
}
|
||||
|
||||
return parent::getURI();
|
||||
}
|
||||
|
||||
public function collectData(){
|
||||
$fullhtml = getSimpleHTMLDOM($this->getURI())
|
||||
or returnServerError('Could not request NovelUpdates, novel "' . $this->getInput('n') . '" not found');
|
||||
@@ -37,16 +41,29 @@ class NovelUpdatesBridge extends BridgeAbstract{
|
||||
$item['title'] = $element->find('td', 2)->find('a', 0)->plaintext;
|
||||
$item['team'] = $element->find('td', 1)->innertext;
|
||||
$item['timestamp'] = strtotime($element->find('td', 0)->plaintext);
|
||||
$item['content'] =
|
||||
'<a href="'.$item['uri'].'">'
|
||||
.$this->seriesTitle.' - '.$item['title']
|
||||
.'</a> by '.$item['team'].'<br>'
|
||||
.'<a href="'.$item['uri'].'">'.$fullhtml->find('div.seriesimg', 0)->innertext.'</a>';
|
||||
$item['content'] = '<a href="'
|
||||
. $item['uri']
|
||||
. '">'
|
||||
. $this->seriesTitle
|
||||
. ' - '
|
||||
. $item['title']
|
||||
. '</a> by '
|
||||
. $item['team']
|
||||
. '<br><a href="'
|
||||
. $item['uri']
|
||||
. '">'
|
||||
. $fullhtml->find('div.seriesimg', 0)->innertext
|
||||
. '</a>';
|
||||
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
if(!empty($this->seriesTitle)) {
|
||||
return $this->seriesTitle . ' - ' . static::NAME;
|
||||
}
|
||||
|
||||
return parent::getName();
|
||||
}
|
||||
}
|
||||
|
@@ -1,11 +1,11 @@
|
||||
<?php
|
||||
class OpenClassroomsBridge extends BridgeAbstract {
|
||||
|
||||
const MAINTAINER = "sebsauvage";
|
||||
const NAME = "OpenClassrooms Bridge";
|
||||
const URI = "https://openclassrooms.com/";
|
||||
const MAINTAINER = 'sebsauvage';
|
||||
const NAME = 'OpenClassrooms Bridge';
|
||||
const URI = 'https://openclassrooms.com/';
|
||||
const CACHE_TIMEOUT = 21600; // 6h
|
||||
const DESCRIPTION = "Returns latest tutorials from OpenClassrooms.";
|
||||
const DESCRIPTION = 'Returns latest tutorials from OpenClassrooms.';
|
||||
|
||||
const PARAMETERS = array( array(
|
||||
'u' => array(
|
||||
@@ -27,8 +27,11 @@ class OpenClassroomsBridge extends BridgeAbstract{
|
||||
));
|
||||
|
||||
public function getURI(){
|
||||
return self::URI.'/courses?categories='.$this->getInput('u').'&'
|
||||
.'title=&sort=updatedAt+desc';
|
||||
if(!is_null($this->getInput('u'))) {
|
||||
return self::URI . '/courses?categories=' . $this->getInput('u') . '&title=&sort=updatedAt+desc';
|
||||
}
|
||||
|
||||
return parent::getURI();
|
||||
}
|
||||
|
||||
public function collectData(){
|
||||
|
@@ -1,12 +1,11 @@
|
||||
<?php
|
||||
class ParuVenduImmoBridge extends BridgeAbstract
|
||||
{
|
||||
const MAINTAINER = "polo2ro";
|
||||
const NAME = "Paru Vendu Immobilier";
|
||||
const URI = "http://www.paruvendu.fr";
|
||||
const CACHE_TIMEOUT = 10800; // 3h
|
||||
const DESCRIPTION = "Returns the ads from the first page of search result.";
|
||||
class ParuVenduImmoBridge extends BridgeAbstract {
|
||||
|
||||
const MAINTAINER = 'polo2ro';
|
||||
const NAME = 'Paru Vendu Immobilier';
|
||||
const URI = 'http://www.paruvendu.fr';
|
||||
const CACHE_TIMEOUT = 10800; // 3h
|
||||
const DESCRIPTION = 'Returns the ads from the first page of search result.';
|
||||
|
||||
const PARAMETERS = array( array(
|
||||
'minarea' => array(
|
||||
@@ -21,11 +20,12 @@ class ParuVenduImmoBridge extends BridgeAbstract
|
||||
'name' => 'Country code',
|
||||
'exampleValue' => 'FR'
|
||||
),
|
||||
'lo'=>array('name'=>'department numbers or postal codes, comma-separated')
|
||||
'lo' => array(
|
||||
'name' => 'department numbers or postal codes, comma-separated'
|
||||
)
|
||||
));
|
||||
|
||||
public function collectData()
|
||||
{
|
||||
public function collectData(){
|
||||
$html = getSimpleHTMLDOM($this->getURI())
|
||||
or returnServerError('Could not request paruvendu.');
|
||||
|
||||
@@ -54,14 +54,16 @@ class ParuVenduImmoBridge extends BridgeAbstract
|
||||
$item['title'] = $element->title;
|
||||
$item['content'] = $img . $desc . $price;
|
||||
$this->items[] = $item;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public function getURI(){
|
||||
$appartment = '&tbApp=1&tbDup=1&tbChb=1&tbLof=1&tbAtl=1&tbPla=1';
|
||||
$maison = '&tbMai=1&tbVil=1&tbCha=1&tbPro=1&tbHot=1&tbMou=1&tbFer=1';
|
||||
$link = self::URI.'/immobilier/annonceimmofo/liste/listeAnnonces?tt=1'.$appartment.$maison;
|
||||
$link = self::URI
|
||||
. '/immobilier/annonceimmofo/liste/listeAnnonces?tt=1'
|
||||
. $appartment
|
||||
. $maison;
|
||||
|
||||
if($this->getInput('minarea')) {
|
||||
$link .= '&sur0=' . urlencode($this->getInput('minarea'));
|
||||
@@ -82,6 +84,7 @@ class ParuVenduImmoBridge extends BridgeAbstract
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
if(!is_null($this->getInput('minarea'))) {
|
||||
$request = '';
|
||||
$minarea = $this->getInput('minarea');
|
||||
if(!empty($minarea)) {
|
||||
@@ -93,4 +96,7 @@ class ParuVenduImmoBridge extends BridgeAbstract
|
||||
}
|
||||
return 'Paru Vendu Immobilier' . $request;
|
||||
}
|
||||
|
||||
return parent::getName();
|
||||
}
|
||||
}
|
||||
|
23
bridges/PcGamerBridge.php
Normal file
23
bridges/PcGamerBridge.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
class PcGamerBridge extends BridgeAbstract
|
||||
{
|
||||
const NAME = 'PC Gamer';
|
||||
const URI = 'https://www.pcgamer.com/';
|
||||
const DESCRIPTION = 'PC Gamer Most Read Stories';
|
||||
const MAINTAINER = 'mdemoss';
|
||||
|
||||
public function collectData()
|
||||
{
|
||||
$html = getSimpleHTMLDOMCached($this->getURI(), 300);
|
||||
$stories = $html->find('div#popularcontent li.most-popular-item');
|
||||
foreach ($stories as $element) {
|
||||
$item['uri'] = $element->find('a', 0)->href;
|
||||
$articleHtml = getSimpleHTMLDOMCached($item['uri']);
|
||||
$item['title'] = $element->find('h4 a', 0)->plaintext;
|
||||
$item['timestamp'] = strtotime($articleHtml->find('meta[name=pub_date]', 0)->content);
|
||||
$item['content'] = $articleHtml->find('meta[name=description]', 0)->content;
|
||||
$item['author'] = $articleHtml->find('a[itemprop=author]', 0)->plaintext;
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,18 +1,20 @@
|
||||
<?php
|
||||
class PickyWallpapersBridge extends BridgeAbstract {
|
||||
|
||||
const MAINTAINER = "nel50n";
|
||||
const NAME = "PickyWallpapers Bridge";
|
||||
const URI = "http://www.pickywallpapers.com/";
|
||||
const MAINTAINER = 'nel50n';
|
||||
const NAME = 'PickyWallpapers Bridge';
|
||||
const URI = 'http://www.pickywallpapers.com/';
|
||||
const CACHE_TIMEOUT = 43200; // 12h
|
||||
const DESCRIPTION = "Returns the latests wallpapers from PickyWallpapers";
|
||||
const DESCRIPTION = 'Returns the latests wallpapers from PickyWallpapers';
|
||||
|
||||
const PARAMETERS = array( array(
|
||||
'c' => array(
|
||||
'name' => 'category',
|
||||
'required' => true
|
||||
),
|
||||
's'=>array('name'=>'subcategory'),
|
||||
's' => array(
|
||||
'name' => 'subcategory'
|
||||
),
|
||||
'm' => array(
|
||||
'name' => 'Max number of wallpapers',
|
||||
'defaultValue' => 12,
|
||||
@@ -26,7 +28,6 @@ class PickyWallpapersBridge extends BridgeAbstract {
|
||||
)
|
||||
));
|
||||
|
||||
|
||||
public function collectData(){
|
||||
$lastpage = 1;
|
||||
$num = 0;
|
||||
@@ -43,12 +44,22 @@ class PickyWallpapersBridge extends BridgeAbstract {
|
||||
}
|
||||
|
||||
foreach($html->find('.items li img') as $element) {
|
||||
|
||||
$item = array();
|
||||
$item['uri'] = str_replace('www', 'wallpaper', self::URI).'/'.$resolution.'/'.basename($element->src);
|
||||
$item['uri'] = str_replace('www', 'wallpaper', self::URI)
|
||||
. '/'
|
||||
. $resolution
|
||||
. '/'
|
||||
. basename($element->src);
|
||||
|
||||
$item['timestamp'] = time();
|
||||
$item['title'] = $element->alt;
|
||||
$item['content'] = $item['title'].'<br><a href="'.$item['uri'].'">'.$element.'</a>';
|
||||
$item['content'] = $item['title']
|
||||
. '<br><a href="'
|
||||
. $item['uri']
|
||||
. '">'
|
||||
. $element
|
||||
. '</a>';
|
||||
|
||||
$this->items[] = $item;
|
||||
|
||||
$num++;
|
||||
@@ -59,15 +70,32 @@ class PickyWallpapersBridge extends BridgeAbstract {
|
||||
}
|
||||
|
||||
public function getURI(){
|
||||
if(!is_null($this->getInput('s')) && !is_null($this->getInput('r')) && !is_null($this->getInput('c'))) {
|
||||
$subcategory = $this->getInput('s');
|
||||
$link = self::URI.$this->getInput('r').'/'.$this->getInput('c').'/'.$subcategory;
|
||||
$link = self::URI
|
||||
. $this->getInput('r')
|
||||
. '/'
|
||||
. $this->getInput('c')
|
||||
. '/'
|
||||
. $subcategory;
|
||||
|
||||
return $link;
|
||||
}
|
||||
|
||||
return parent::getURI();
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
if(!is_null($this->getInput('s'))) {
|
||||
$subcategory = $this->getInput('s');
|
||||
return 'PickyWallpapers - '.$this->getInput('c')
|
||||
return 'PickyWallpapers - '
|
||||
. $this->getInput('c')
|
||||
. ($subcategory ? ' > ' . $subcategory : '')
|
||||
.' ['.$this->getInput('r').']';
|
||||
. ' ['
|
||||
. $this->getInput('r')
|
||||
. ']';
|
||||
}
|
||||
|
||||
return parent::getName();
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user