mirror of
https://github.com/RSS-Bridge/rss-bridge.git
synced 2025-08-17 22:02:09 +02:00
Compare commits
1352 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
71fc854663 | ||
|
120612424c | ||
|
33ecaa0b7b | ||
|
7ce57aefbe | ||
|
72981032e4 | ||
|
d06006d681 | ||
|
d39c1ed63a | ||
|
04a195361a | ||
|
3bcd98404b | ||
|
8924722b93 | ||
|
5790ebc6ba | ||
|
38f197fb60 | ||
|
6a6ccee3cd | ||
|
85149add61 | ||
|
5258551a98 | ||
|
6c4d28c849 | ||
|
49281a2ed3 | ||
|
ffb584f7de | ||
|
82ed2c5ffb | ||
|
46ce0f85d7 | ||
|
b6feda2377 | ||
|
8fb4db8914 | ||
|
5c309e93dc | ||
|
2d56b717cf | ||
|
5639b158e7 | ||
|
5de4a59d41 | ||
|
d941fa41f6 | ||
|
ac0a9a90ad | ||
|
5ccde61a19 | ||
|
0998cbde9d | ||
|
5f1c4e1c55 | ||
|
ad825aa88a | ||
|
45890d5969 | ||
|
5fdb3b2fd9 | ||
|
9ac678aac5 | ||
|
51ff8de346 | ||
|
0e9fb31986 | ||
|
3e82a82499 | ||
|
381a452047 | ||
|
aa2442602a | ||
|
f8dafe6b10 | ||
|
952bde0425 | ||
|
41e85bd4a6 | ||
|
5662dff5cb | ||
|
9e209608c8 | ||
|
c0df82c303 | ||
|
95bd44e3fb | ||
|
885198d8d2 | ||
|
8b6ee19aba | ||
|
b61ea84950 | ||
|
ee7ddcf992 | ||
|
f0f0ffb96a | ||
|
b32cfd5dc3 | ||
|
b0784e5a42 | ||
|
978e5cdbf5 | ||
|
4b171f8f46 | ||
|
970e216c1f | ||
|
9020b09fc2 | ||
|
7bb464350c | ||
|
177d3d1c5f | ||
|
a4db8dc495 | ||
|
b50652e6ac | ||
|
3dcdaa1595 | ||
|
a1ef589ffe | ||
|
747be13849 | ||
|
f1fb95b257 | ||
|
235c985901 | ||
|
41540e24ef | ||
|
69d30ad125 | ||
|
c5831e384f | ||
|
ad534444fa | ||
|
43aeb61a7b | ||
|
47200752fb | ||
|
5547de1785 | ||
|
b3a36a2697 | ||
|
957ae5d379 | ||
|
0eeb511676 | ||
|
691d4ad0ee | ||
|
120247256d | ||
|
19a4880c86 | ||
|
ec3824e284 | ||
|
351eb00400 | ||
|
2331c4fbab | ||
|
ac3a2b8e6e | ||
|
3438b96197 | ||
|
ce92edb0ba | ||
|
c5e7a18c5e | ||
|
e0407326c3 | ||
|
c3a1cbe98a | ||
|
7ae64fcd05 | ||
|
294d89bd36 | ||
|
3fa965cf3c | ||
|
70c490d6ef | ||
|
2ca7129e22 | ||
|
10ac808580 | ||
|
3f64d2d65a | ||
|
43ac961284 | ||
|
b6245a90c8 | ||
|
ca0842ccf8 | ||
|
4c3b80fca9 | ||
|
b5358d6cea | ||
|
2744c13735 | ||
|
8f58c9f86b | ||
|
244516f0a2 | ||
|
6f8b93fb46 | ||
|
f8e0a4afbc | ||
|
c1cc4da8ef | ||
|
1819943451 | ||
|
ffc9418620 | ||
|
a333226733 | ||
|
ed423969ac | ||
|
8ae9275ffd | ||
|
3bacb407fe | ||
|
15c422c648 | ||
|
655b3d578d | ||
|
6943abd9c2 | ||
|
88919a43fd | ||
|
e3392a738b | ||
|
ab16af631e | ||
|
62eec43980 | ||
|
32ce2b6541 | ||
|
d17998224e | ||
|
3942b6b86f | ||
|
ccc816eae8 | ||
|
5ad2e38927 | ||
|
9be03f199b | ||
|
22cf562659 | ||
|
2eec89ab27 | ||
|
7b5e367678 | ||
|
9f2dd48684 | ||
|
a726f73afe | ||
|
bf8214e3dd | ||
|
73b4aea084 | ||
|
33584b8423 | ||
|
3a94956915 | ||
|
3a92a1e04b | ||
|
1a2a48e129 | ||
|
ce00c6f869 | ||
|
84956c4daf | ||
|
9711e87fc9 | ||
|
8c71a35771 | ||
|
c383f8697a | ||
|
579d13462f | ||
|
2861a855e4 | ||
|
f1fb527607 | ||
|
179e73fb80 | ||
|
11be7ccb60 | ||
|
298dc49c67 | ||
|
d98bb25de6 | ||
|
a0dfbe6efd | ||
|
3daeacc208 | ||
|
0c139941d9 | ||
|
d60220769e | ||
|
fec864e010 | ||
|
671703cd37 | ||
|
15f24b3cf4 | ||
|
acde8a2cea | ||
|
778bbd8d85 | ||
|
78050972f4 | ||
|
88f52196b8 | ||
|
546c0036df | ||
|
878db6f96e | ||
|
39788485ea | ||
|
e30ce8aea0 | ||
|
cd361f8fc0 | ||
|
1de148bf5d | ||
|
0770ca1ad1 | ||
|
149b64879e | ||
|
8fa0b9660f | ||
|
bf20a2f687 | ||
|
51a3a75aac | ||
|
f781965825 | ||
|
0e5775012f | ||
|
e7f2bf19f3 | ||
|
fd6bcbbafe | ||
|
8ae05a0241 | ||
|
97926b839e | ||
|
147154f44c | ||
|
d8ebcc9376 | ||
|
e5a375ab48 | ||
|
2aa9b8f026 | ||
|
c365f35e47 | ||
|
99f00e57b5 | ||
|
f9a8f16685 | ||
|
6c51eaa4d7 | ||
|
4c96aab832 | ||
|
013a4c0428 | ||
|
a8883523f4 | ||
|
d1ff23c7ba | ||
|
04bddd0758 | ||
|
5f3d60276a | ||
|
cbea717e80 | ||
|
4bc4e03d7b | ||
|
41d3aa0695 | ||
|
48db1693a1 | ||
|
c2e411ba82 | ||
|
37f269cf53 | ||
|
d520e82d9e | ||
|
5ad1fa8242 | ||
|
cc46cf58ba | ||
|
c0c10836d6 | ||
|
9a0da733ef | ||
|
556b8a2452 | ||
|
729cbadc77 | ||
|
948bd9ae31 | ||
|
c642fca0d0 | ||
|
1aa01a1f67 | ||
|
47b6cb8937 | ||
|
7c36b51aa2 | ||
|
cd9435b936 | ||
|
85a025a82b | ||
|
9d7e64fac0 | ||
|
abc4f047bf | ||
|
468aa28a67 | ||
|
2cda7edcbd | ||
|
6e3f08e9d3 | ||
|
23bb5c5dfb | ||
|
014d016a51 | ||
|
ada5903d68 | ||
|
83fad77a08 | ||
|
55c406e1b4 | ||
|
0262162bc3 | ||
|
351e1e9a6a | ||
|
fa294e2b4c | ||
|
f79d699a59 | ||
|
9b5177eb68 | ||
|
5093eadfca | ||
|
3212c33770 | ||
|
0f2cfe06d3 | ||
|
eae88cf2cf | ||
|
1f72a34b42 | ||
|
0b482283cb | ||
|
cf70e43f59 | ||
|
a88ad96ad9 | ||
|
82b150baa8 | ||
|
aed7815f05 | ||
|
b1d9d88772 | ||
|
92e0bec925 | ||
|
1172bea2db | ||
|
10d5bb630f | ||
|
5704b6e3c4 | ||
|
927ae17d5c | ||
|
75a6f8af8a | ||
|
9f82adc87b | ||
|
08158825d9 | ||
|
662c1b6410 | ||
|
75f312ea7b | ||
|
5f0b843453 | ||
|
0b4854ccbf | ||
|
41dfc57103 | ||
|
370530b5ef | ||
|
8d050c233b | ||
|
f49fca516d | ||
|
e46a480c5d | ||
|
5d0ee926a5 | ||
|
cf146523be | ||
|
a84016bcb6 | ||
|
1e9b5c8611 | ||
|
059b099436 | ||
|
3c1706aa47 | ||
|
7de22c3e9a | ||
|
57fd0255ff | ||
|
3fb8c5b916 | ||
|
03cbd756a6 | ||
|
b547285b88 | ||
|
9c1c29ec74 | ||
|
73dd97aa6b | ||
|
79c536c189 | ||
|
a52a5b881a | ||
|
75d429bcf3 | ||
|
d2bbe3a1f4 | ||
|
b1a834801b | ||
|
6fa2d18516 | ||
|
c53210b434 | ||
|
98ebed9bc0 | ||
|
01e0f2f77a | ||
|
820eb5377b | ||
|
30f4a3f0f9 | ||
|
69f5c6fa75 | ||
|
0668f79704 | ||
|
953faabb1a | ||
|
453cacf490 | ||
|
7c03437c57 | ||
|
df80500c51 | ||
|
f13f44a682 | ||
|
b5c432d66c | ||
|
39d980dd3d | ||
|
7d9d6f3d79 | ||
|
86a6f68af4 | ||
|
37d2e75d7d | ||
|
8e3f6dbc73 | ||
|
2496f1374d | ||
|
88f5014a16 | ||
|
9f6aff9699 | ||
|
0fea61a470 | ||
|
7c840093db | ||
|
dc358dea9b | ||
|
05825cf6f7 | ||
|
2ca854cacf | ||
|
836eb8c038 | ||
|
6ea946359c | ||
|
0d9be1f510 | ||
|
445f3336c0 | ||
|
e139372255 | ||
|
29b4f954c2 | ||
|
4f7fbae861 | ||
|
8ed3b02899 | ||
|
7e2129fa2a | ||
|
78f6757622 | ||
|
e4b314f78a | ||
|
7363acfa6b | ||
|
a7b3519c35 | ||
|
5f3d28f3a6 | ||
|
8c7b53b883 | ||
|
342de7744b | ||
|
d4d635a7d2 | ||
|
cee272ba6e | ||
|
d0cfeed3cf | ||
|
3df0f299de | ||
|
b1e5c7870f | ||
|
7cfc35d20c | ||
|
c3086fa20b | ||
|
c9d89aface | ||
|
ebe7084cc2 | ||
|
2238e8998a | ||
|
f1a3ed297e | ||
|
a80246a2b3 | ||
|
963bbcc402 | ||
|
6f8a773260 | ||
|
4959334f9f | ||
|
c2ea8d0ee9 | ||
|
58f6a43574 | ||
|
7710613e62 | ||
|
3d76ac5d17 | ||
|
6b97ca2991 | ||
|
88521f188e | ||
|
1068f31303 | ||
|
efb6ad9ff2 | ||
|
ff5ac1659f | ||
|
fb05976fa6 | ||
|
e74f526c19 | ||
|
74d876b585 | ||
|
806f38b42d | ||
|
c37aee408d | ||
|
93634ada3a | ||
|
3fed12af1d | ||
|
e9ff7b32f1 | ||
|
16dc7fcb6f | ||
|
fa7cd4a739 | ||
|
1b3c8a8aeb | ||
|
a4fd7b8b98 | ||
|
2047955f06 | ||
|
d1715f6efc | ||
|
ea46d532dc | ||
|
85625318b1 | ||
|
ea1d53a24a | ||
|
701aff420d | ||
|
de1b39c8e5 | ||
|
2301a12cc6 | ||
|
792578aefb | ||
|
a24e6ea323 | ||
|
0de4fce41d | ||
|
341ce2bf3e | ||
|
720b7924c5 | ||
|
7857325d9c | ||
|
72e3031d5c | ||
|
05001f6b2e | ||
|
292f0f85ad | ||
|
614d425da4 | ||
|
760141a751 | ||
|
d95fa6117a | ||
|
c061057861 | ||
|
2f1fa81082 | ||
|
ed0fd12193 | ||
|
0d36ca21df | ||
|
1de7fb748c | ||
|
755d3e133f | ||
|
a8797641fd | ||
|
84c45e459e | ||
|
5448edcd79 | ||
|
0fcde196b9 | ||
|
737942ae7a | ||
|
accbe8c06f | ||
|
449b2ca520 | ||
|
3f36ca2a9b | ||
|
2670a0e400 | ||
|
b676eca0a2 | ||
|
5e33a27f7c | ||
|
23a7edebd6 | ||
|
b6fe424ddb | ||
|
3a0a2a9559 | ||
|
a67a219bf9 | ||
|
3bad5ec45c | ||
|
af1673d1c4 | ||
|
c34fdfa7fb | ||
|
117031bf0f | ||
|
dea37c8e34 | ||
|
1bb94aecc6 | ||
|
70a8b88b6f | ||
|
ca9879fac9 | ||
|
946a0744ed | ||
|
6dd45eae57 | ||
|
b9207841cc | ||
|
d530415481 | ||
|
5b32050a6e | ||
|
fbf17beae8 | ||
|
73ec10f9ca | ||
|
99a416ebad | ||
|
1d0b8f20f3 | ||
|
95404b8fc4 | ||
|
b9b2428f63 | ||
|
458d1fbfeb | ||
|
56cb116ce6 | ||
|
5a7bc9b0c3 | ||
|
8252387386 | ||
|
9021a4b7cc | ||
|
429126e18a | ||
|
a43703d32d | ||
|
237a26e4ff | ||
|
07f664b2fa | ||
|
1e9edf49de | ||
|
c0c4759cde | ||
|
d80efed1f4 | ||
|
c051730f7c | ||
|
c9822bffa7 | ||
|
7961f8081e | ||
|
9173e7da54 | ||
|
c94cfce511 | ||
|
a8b445724f | ||
|
b31b6667f6 | ||
|
3c089c1b11 | ||
|
7e0ac1a6b6 | ||
|
0a86d572c2 | ||
|
581bff166c | ||
|
eb3392db82 | ||
|
13285f080a | ||
|
b3af604cc1 | ||
|
4a1f360d39 | ||
|
747e54d64a | ||
|
8283a5a34f | ||
|
d9b6477ff6 | ||
|
d5db4f5859 | ||
|
7b890da8f2 | ||
|
bf0a9d754e | ||
|
1f3361c6b4 | ||
|
6fd0bdd21e | ||
|
d5418b3d11 | ||
|
dc4f16fbe4 | ||
|
f0e502ce37 | ||
|
2f09ae56ad | ||
|
4717de9d08 | ||
|
ee2b9d65ee | ||
|
306d50582d | ||
|
b5cc7b4ded | ||
|
4aaa921696 | ||
|
af747af534 | ||
|
bbf95662c2 | ||
|
c54462d2f0 | ||
|
f9b5cac1b7 | ||
|
bdb1871474 | ||
|
8adcc7d26a | ||
|
f29d51510b | ||
|
5e52f4d3e6 | ||
|
84238a998d | ||
|
4540645122 | ||
|
8e32142ce5 | ||
|
181be164e0 | ||
|
7641fb5266 | ||
|
b97317af2e | ||
|
09bc211cc6 | ||
|
be98ad161a | ||
|
5410392968 | ||
|
cd088776a8 | ||
|
2466f109b8 | ||
|
dd1474f154 | ||
|
fd5c8ea658 | ||
|
bba216073c | ||
|
d0461f3643 | ||
|
6e66c228f8 | ||
|
71d8f4c465 | ||
|
7761d1b70a | ||
|
490c5094f5 | ||
|
9cc00cb212 | ||
|
251d7646b7 | ||
|
6a912fba96 | ||
|
67d6802161 | ||
|
be591d19e0 | ||
|
10cd3a61a9 | ||
|
e754ca52e9 | ||
|
6e2c7ceaf4 | ||
|
86515a1560 | ||
|
226484ba22 | ||
|
fe58d23c17 | ||
|
d74beb6c6a | ||
|
3c0d13c1bb | ||
|
f43bbda83e | ||
|
d71674d2ba | ||
|
09d4e21bdc | ||
|
3dd63ab6fd | ||
|
b43e8ef689 | ||
|
5986b9f786 | ||
|
1e953d3c3e | ||
|
65c6b08aed | ||
|
74f0572d91 | ||
|
73a1bcf3d6 | ||
|
d3cebe9c65 | ||
|
5212b91cca | ||
|
eb419e2595 | ||
|
d3cbf38eb1 | ||
|
646ae57326 | ||
|
a6da16feb7 | ||
|
5d66af7a29 | ||
|
3fd283e29f | ||
|
3ca2f030e7 | ||
|
f853f62270 | ||
|
fa59a25229 | ||
|
c689180fef | ||
|
a70e143dc4 | ||
|
43dce4b228 | ||
|
a2ecf5d943 | ||
|
ceb3e9a039 | ||
|
a5c7179b0e | ||
|
94404aad61 | ||
|
890b48c56d | ||
|
0e7f992e64 | ||
|
eeb6c9681d | ||
|
619f4898fa | ||
|
c9fd3979c1 | ||
|
69a590be79 | ||
|
213241527d | ||
|
2a04940fb8 | ||
|
f0f2e8f847 | ||
|
cd7eb1b8fe | ||
|
0c1ec44c49 | ||
|
68d1c1f961 | ||
|
1ea38d521d | ||
|
5ef26343b3 | ||
|
a628abd04c | ||
|
89aad9f796 | ||
|
6138031793 | ||
|
faacbda027 | ||
|
0683457eb3 | ||
|
13d9b8d462 | ||
|
1a572f6639 | ||
|
63bb7ef24d | ||
|
9f3e7e1da7 | ||
|
d79366f479 | ||
|
606e756bc1 | ||
|
0d94f1fe0e | ||
|
8b468e94a8 | ||
|
ae716abf65 | ||
|
368fc66fbf | ||
|
e3c578510b | ||
|
be487a6950 | ||
|
42b6c82753 | ||
|
e329a4c1b6 | ||
|
4806092b9f | ||
|
8c21769078 | ||
|
f3eefab475 | ||
|
1af6008d65 | ||
|
0663c9507f | ||
|
bb49aef187 | ||
|
c0b607c841 | ||
|
82f06ad2c5 | ||
|
3f83763ff9 | ||
|
75f7a32b99 | ||
|
d98a7d6644 | ||
|
73dc0efac6 | ||
|
13d42746d7 | ||
|
1cfb8c02a0 | ||
|
04b4dd1db9 | ||
|
17c9d8fc37 | ||
|
0b923ab76a | ||
|
d4435e0b13 | ||
|
2c954a848d | ||
|
3d72ba8ed9 | ||
|
7d073b3e96 | ||
|
62c77384ec | ||
|
0ddf664d89 | ||
|
a1257126bc | ||
|
b59915f23b | ||
|
5432cabef5 | ||
|
5ad157d2fd | ||
|
1d53b70272 | ||
|
f99f4d23ac | ||
|
48711bd772 | ||
|
5b7a6300ec | ||
|
67e2698211 | ||
|
a5120dde2c | ||
|
db95a2afca | ||
|
09309db86b | ||
|
e4a56e504e | ||
|
31bdf7390a | ||
|
e6bd815bcc | ||
|
da1e32267b | ||
|
02e169584a | ||
|
12abf9d455 | ||
|
7afee0e277 | ||
|
870ef6f6fc | ||
|
2c41ed550d | ||
|
d944558a3d | ||
|
455b98757c | ||
|
21523eb549 | ||
|
2672b96e11 | ||
|
eb8ffe97a9 | ||
|
0a008c4eb3 | ||
|
905b0f2499 | ||
|
064f456be1 | ||
|
652d3eca3d | ||
|
68be407564 | ||
|
a53c458d5a | ||
|
1cbc045703 | ||
|
737199404c | ||
|
559471de8a | ||
|
0db1c86db9 | ||
|
8cbca68b8a | ||
|
628e133e96 | ||
|
f1f67f35d3 | ||
|
c113b01f01 | ||
|
6162164bd4 | ||
|
d6ff40c527 | ||
|
0cb66e2194 | ||
|
2913f86684 | ||
|
77f326e377 | ||
|
e8473bf95e | ||
|
f8cb976e2c | ||
|
6f248f5973 | ||
|
9495e830e7 | ||
|
0737833c88 | ||
|
086dbd5002 | ||
|
6c97b41899 | ||
|
2044a34bae | ||
|
0241ddb0e8 | ||
|
ec5cb657aa | ||
|
0a34fd5a7e | ||
|
d6e7b75b42 | ||
|
6ee3165d6f | ||
|
b889b51a9e | ||
|
58322137d3 | ||
|
1afdf9cef7 | ||
|
924e123ba6 | ||
|
1d58809676 | ||
|
86fd1c92ea | ||
|
67f5fd0860 | ||
|
47f382ce3f | ||
|
da3127e31b | ||
|
83d7f138ed | ||
|
2a02023c8a | ||
|
1b02330302 | ||
|
aae4d3efec | ||
|
a124d4eb43 | ||
|
6ff73d47bb | ||
|
a43578c6c6 | ||
|
91032bf4fa | ||
|
c36f76be7d | ||
|
b344f50784 | ||
|
b0dce860f7 | ||
|
a1a44cd1ff | ||
|
4f9e03f346 | ||
|
7740dbfcc9 | ||
|
58b3261fbb | ||
|
7ff901de08 | ||
|
d3e5711601 | ||
|
e7e2101889 | ||
|
173afb8314 | ||
|
71d868fd90 | ||
|
8ba8fea263 | ||
|
84847bf85f | ||
|
6b7b38db54 | ||
|
a1c680f8e8 | ||
|
f783969721 | ||
|
399fce06ce | ||
|
8f76eebddb | ||
|
d3d379bd81 | ||
|
ab4e63b59c | ||
|
72e457a5b7 | ||
|
cd5f3e740a | ||
|
3a0675364f | ||
|
0bb11db536 | ||
|
f3d3582af1 | ||
|
c8c3e9ef65 | ||
|
3cc262443c | ||
|
0f3ca30caa | ||
|
4420906a7a | ||
|
0631e9d835 | ||
|
0052f25d2a | ||
|
cb7d477310 | ||
|
5fb27b2aa6 | ||
|
c75622135e | ||
|
cb84635e2d | ||
|
9af011cee1 | ||
|
dfa6dc33aa | ||
|
b3a3328600 | ||
|
a32044893a | ||
|
ea4586d8b3 | ||
|
d0c932c149 | ||
|
099a421d8b | ||
|
fa7a053c65 | ||
|
01bdda5e19 | ||
|
1e33b7c2ec | ||
|
a84f11aed8 | ||
|
4a001f3594 | ||
|
5189741c7b | ||
|
371a52e2b9 | ||
|
9d41c83c02 | ||
|
e3cf486ac5 | ||
|
b37877bc74 | ||
|
fb595484b5 | ||
|
81b6238ee4 | ||
|
d60a822bc2 | ||
|
9b579c7cd4 | ||
|
74b6dd37f9 | ||
|
a5b8c8d422 | ||
|
f72cde7fa1 | ||
|
8831ad068e | ||
|
48883a9cc4 | ||
|
dfc4e8aaac | ||
|
80651273b3 | ||
|
400305f9d3 | ||
|
94289511e1 | ||
|
a9e6f5514e | ||
|
3a69573b27 | ||
|
0454fcc780 | ||
|
c6190514c4 | ||
|
d5eb53ecd2 | ||
|
2f3bddb291 | ||
|
0e27a6ebab | ||
|
95acb218b4 | ||
|
b0892fdb70 | ||
|
6abca16f06 | ||
|
5353697e67 | ||
|
980075c8f9 | ||
|
f05bd15393 | ||
|
4b179144c1 | ||
|
5a60f892eb | ||
|
9519cc24ab | ||
|
90ae96efe9 | ||
|
b013845a5d | ||
|
66c79e4b67 | ||
|
f6cbb5c7ce | ||
|
26a9ffa5eb | ||
|
ca44ab943a | ||
|
615df56b19 | ||
|
c929010f6e | ||
|
e03a7de15f | ||
|
d45c6be3c5 | ||
|
aa96c6b1d2 | ||
|
d73bfbab63 | ||
|
78b4500ba4 | ||
|
3922b9534c | ||
|
1f85a2294d | ||
|
dc6928316b | ||
|
06f8b61f62 | ||
|
955eecc299 | ||
|
36d39d3f59 | ||
|
fdd8d0cd04 | ||
|
040f4da73d | ||
|
d27929668f | ||
|
b707a29b7e | ||
|
7c62bf070b | ||
|
d624d0de92 | ||
|
c0e82017bd | ||
|
a63773178a | ||
|
96de64af63 | ||
|
83adf25c56 | ||
|
feb34c9eb1 | ||
|
973f0ba8d8 | ||
|
f64664a83c | ||
|
ce6f7478f0 | ||
|
0a35003237 | ||
|
8461c66582 | ||
|
24a312a158 | ||
|
8a00c9d407 | ||
|
a04d7ba8eb | ||
|
ba400d561e | ||
|
f72d78d84b | ||
|
f5a1af4a85 | ||
|
269e6494ed | ||
|
5a2fbd94b2 | ||
|
a6e403f48d | ||
|
ac675acf50 | ||
|
f9389cf7be | ||
|
02bdc1dfbe | ||
|
346a741424 | ||
|
ca04246eb0 | ||
|
5d87f1f8ef | ||
|
6a768b4dfc | ||
|
796c14758f | ||
|
642e4173d1 | ||
|
832c503278 | ||
|
b1cb8e9b6e | ||
|
bfaade37ab | ||
|
cd5d8b8953 | ||
|
382ef28abe | ||
|
88a78b5666 | ||
|
de4952d31f | ||
|
99b7d2e6b4 | ||
|
75a6a8ee5c | ||
|
2c08c92dfe | ||
|
3d4e3679ad | ||
|
421c47d9ed | ||
|
3288328ff7 | ||
|
e62c6af62e | ||
|
ff63a5ad95 | ||
|
d2d0f94e18 | ||
|
dca001dffc | ||
|
3bf8e98e3c | ||
|
8e7dd0f4da | ||
|
a46ce5070e | ||
|
7235704a2b | ||
|
df39c8c18f | ||
|
3318e66cbc | ||
|
599e36a9ac | ||
|
7f65085b84 | ||
|
b2f42144f8 | ||
|
0ff3cf0e0b | ||
|
e11123775a | ||
|
d7f079e66b | ||
|
c2769c8999 | ||
|
c13dd8c18a | ||
|
9df5913d6b | ||
|
3e8a7624e1 | ||
|
084eb4c9f4 | ||
|
333d8d0c30 | ||
|
386f0ca379 | ||
|
05c2e2aa20 | ||
|
9553505bdd | ||
|
54e912805e | ||
|
5f35988a18 | ||
|
ffa1ea8f0f | ||
|
1d44dafdef | ||
|
4fac0e382c | ||
|
d18055720a | ||
|
b0c15c3377 | ||
|
641d5880c7 | ||
|
937ef6b979 | ||
|
d0defc6283 | ||
|
21ed355343 | ||
|
d92dc71fae | ||
|
e064b5fe28 | ||
|
ef46bddbc9 | ||
|
1c1bcc20ff | ||
|
036ea43e4f | ||
|
8f6b5f5731 | ||
|
04ec53010c | ||
|
f09dedf16b | ||
|
ca2951df30 | ||
|
4c241a1319 | ||
|
ab2492f292 | ||
|
36735e7c5a | ||
|
2a621f1506 | ||
|
11336bc109 | ||
|
0071a9fe2c | ||
|
84356487e9 | ||
|
26e02ef3b6 | ||
|
834f959b76 | ||
|
dd0be3f4db | ||
|
9153071a0e | ||
|
b7fa3188ac | ||
|
54812d626e | ||
|
4ccd1b84e5 | ||
|
91fe6c4acc | ||
|
bba6a0b5c2 | ||
|
a9c40e98c4 | ||
|
705b266c28 | ||
|
f8b9470622 | ||
|
e1b7ffdc81 | ||
|
47dd6c3b03 | ||
|
541ba9116a | ||
|
4bd04a1023 | ||
|
a58cc65957 | ||
|
65a9c2b0bc | ||
|
f837032afb | ||
|
651f5ac94f | ||
|
abce3186d4 | ||
|
787de0360c | ||
|
57de433553 | ||
|
445568db27 | ||
|
d16d514736 | ||
|
1e998ab6dd | ||
|
c375384fba | ||
|
e2043574f2 | ||
|
d1fe87651d | ||
|
182dcbec60 | ||
|
621c7af6b7 | ||
|
b5c7566b7a | ||
|
4ffe329089 | ||
|
e59bf64c42 | ||
|
f22b4b33df | ||
|
4422024cfd | ||
|
cfac9e72f2 | ||
|
a73807130a | ||
|
170818a625 | ||
|
58e828e69a | ||
|
8db5dde69d | ||
|
48b53b7c03 | ||
|
0e1b84263e | ||
|
2e4e0077a8 | ||
|
195ba94115 | ||
|
438a389286 | ||
|
33c6495333 | ||
|
79a610ea69 | ||
|
31177912e0 | ||
|
2458e369c4 | ||
|
4deefdfd7d | ||
|
e7595391cd | ||
|
259e5ef9de | ||
|
5f01b7fe7d | ||
|
379c89045b | ||
|
e6f388d6e4 | ||
|
6deebb56a5 | ||
|
ff9c60f53c | ||
|
2aba815b55 | ||
|
29481c73c1 | ||
|
7e91186c6c | ||
|
15021ebd78 | ||
|
ac284f3ea4 | ||
|
d885897c40 | ||
|
e4d31c3294 | ||
|
5ada7afcd1 | ||
|
47a79f821a | ||
|
6a2c92a389 | ||
|
7d03d72708 | ||
|
9c8f552a2a | ||
|
e5f887ec1c | ||
|
55d4c6e425 | ||
|
9090c2e470 | ||
|
4c86f38306 | ||
|
b8ec283458 | ||
|
e5c4e053ed | ||
|
6866e508cb | ||
|
1a4a428449 | ||
|
e582c887fb | ||
|
38829e7739 | ||
|
80008f01f8 | ||
|
78c9dcc705 | ||
|
715ad3bf3f | ||
|
53ac336111 | ||
|
b3733069d4 | ||
|
2e4e89aff8 | ||
|
3cb652b812 | ||
|
2d526f4e0a | ||
|
11ad75c7e6 | ||
|
5d2e7ac83d | ||
|
2deef45867 | ||
|
e9e7a421ff | ||
|
a40bbbd2de | ||
|
f386fc4a10 | ||
|
c13c7a1d25 | ||
|
40fdb17280 | ||
|
b2b0ea6a44 | ||
|
a07839019e | ||
|
4c120cd831 | ||
|
e1cdca6971 | ||
|
10c3dfa60e | ||
|
b0305430c7 | ||
|
985ce7a35f | ||
|
d033bb51ac | ||
|
4da956f365 | ||
|
600111efc4 | ||
|
7268dbaae3 | ||
|
2b54377148 | ||
|
ca2f6f425d | ||
|
eaa8cf4173 | ||
|
fe37f9711f | ||
|
6c420883f2 | ||
|
43f0fc93b7 | ||
|
d0c5d5f8ca | ||
|
ffc01fa3bd | ||
|
1efaba5c7c | ||
|
a5a959dced | ||
|
894eadbbda | ||
|
98b2019831 | ||
|
1c869631d6 | ||
|
c204b9d914 | ||
|
ba161b0b12 | ||
|
b339f157c1 | ||
|
871efdd5ce | ||
|
42fc08b93d | ||
|
0eb7731481 | ||
|
182be9b575 | ||
|
60a82b52b7 | ||
|
3115cd8e3a | ||
|
fcc072170c | ||
|
e1dac3abb3 | ||
|
d90b118671 | ||
|
b592f8ebbf | ||
|
23f0fa3ed8 | ||
|
52bdc39948 | ||
|
a1b4414da3 | ||
|
c8ef31bac6 | ||
|
300b8bba9b | ||
|
3780eb58bd | ||
|
0051615b82 | ||
|
5c987b74d5 | ||
|
ea7c8cc314 | ||
|
44edc7fc22 | ||
|
f036bff6b4 | ||
|
e7966dd102 | ||
|
24f3bb84d8 | ||
|
e261c9a594 | ||
|
b39cac116d | ||
|
33dea43bcf | ||
|
497d3fd7aa | ||
|
372ddf2792 | ||
|
85ebb70b74 | ||
|
35ac1d76b2 | ||
|
c17fe0c898 | ||
|
01d6859f77 | ||
|
f11d6fc2ad | ||
|
36ba93eea3 | ||
|
eb24487807 | ||
|
81f89b1246 | ||
|
c030d011d2 | ||
|
f643617cac | ||
|
2c18ee2d53 | ||
|
91b1415e3d | ||
|
8edddcd97f | ||
|
5b2c8e91d0 | ||
|
8b9c40534b | ||
|
d7436c2d0a | ||
|
762ad0291e | ||
|
88bf15e46c | ||
|
80fe041f32 | ||
|
063ee612cf | ||
|
ee4d4d9603 | ||
|
a9052b211e | ||
|
7b9c180654 | ||
|
b58a84537d | ||
|
9dfa1d6f25 | ||
|
7680b065b5 | ||
|
221ac239e1 | ||
|
f8d1322ee7 | ||
|
9f93656bf4 | ||
|
d39336525d | ||
|
d95f4024f5 | ||
|
ce89ed0fc5 | ||
|
1678378bab | ||
|
9bf493cf92 | ||
|
fde1dfa194 | ||
|
17e887631c | ||
|
1055fd4e8b | ||
|
6456d145a0 | ||
|
6003daff9d | ||
|
7b99ad3650 | ||
|
94ffb22fb0 | ||
|
9712d052b4 | ||
|
95af72349b | ||
|
9ce826f78e | ||
|
d9b2f267c5 | ||
|
b18990872e | ||
|
7a40584864 | ||
|
1374b7f563 | ||
|
c16747757d | ||
|
54c5e9f5ea | ||
|
75585e7b52 | ||
|
de16ba234e | ||
|
5b71d587e2 | ||
|
22f0017dc7 | ||
|
222073248d | ||
|
ca9cc12b0c | ||
|
5a2a6fbdba | ||
|
4ca9339e03 | ||
|
d1c4847d88 | ||
|
a8656ac459 | ||
|
4524feeebc | ||
|
7a5b51b8cf | ||
|
5c37fd4dcf | ||
|
2a80794d09 | ||
|
472b7f7255 | ||
|
d80b11f0fa | ||
|
3506a18a39 | ||
|
76907287f0 | ||
|
f1d74a4a27 | ||
|
4e95599d8d | ||
|
0890b52b4c | ||
|
7be284407a | ||
|
ef0329b09c | ||
|
466a139ce3 | ||
|
42c94566d1 | ||
|
0f6fdb0c5b | ||
|
a5f52b8789 | ||
|
a1ccad3d5f | ||
|
2633516df8 | ||
|
1530738a19 | ||
|
47cdb21c6d | ||
|
d35dd8b0ce | ||
|
38ba4cd44f | ||
|
410d0a6d88 | ||
|
ce28cfad22 | ||
|
9861bc0230 | ||
|
ddf7c33b4e | ||
|
aa9e5332a2 | ||
|
14af7d93ba | ||
|
401663aac0 | ||
|
08a349890d | ||
|
91737f3a97 | ||
|
c8dccf76a6 | ||
|
ea5f91f394 | ||
|
25bc285083 | ||
|
8e44a01b2a | ||
|
a2bacd09eb | ||
|
5144c83c95 | ||
|
9171be9c50 | ||
|
ade723f6a6 | ||
|
1a673766ec | ||
|
4b04a77b00 | ||
|
3b69c71197 | ||
|
9cd174ceab | ||
|
e1b5c9cda3 | ||
|
c44c569aa5 | ||
|
091bf7872e | ||
|
a71bb5bc00 | ||
|
fcda5403c1 | ||
|
f7a7acfde4 | ||
|
1a64a21d50 | ||
|
a3d5a1efea | ||
|
05216d9c39 | ||
|
180e74d572 | ||
|
c1fab7971c | ||
|
cd1740bd56 | ||
|
4c48e85e12 | ||
|
bb2c04bbf8 | ||
|
d8bed9aa75 | ||
|
92cb904374 | ||
|
284e103326 | ||
|
368b73f5d7 | ||
|
041a57db1c | ||
|
7b789bf802 | ||
|
840209908e | ||
|
47c22e94aa | ||
|
768a8a29d7 | ||
|
355ed8a1db | ||
|
c51fc40d17 | ||
|
11aeb8088a | ||
|
ab3582e2b4 | ||
|
ff4ccf985f | ||
|
30f339e3b2 | ||
|
0d9df394dd | ||
|
068557ed08 | ||
|
5922e37bc0 | ||
|
d77eea7f09 | ||
|
529c1817f5 | ||
|
f566981470 | ||
|
950b3297e0 | ||
|
bb9d8023ac | ||
|
e4b2a0b29c | ||
|
2e2cf98eb6 | ||
|
4e9a0df1bd | ||
|
119c30b999 | ||
|
5f64a2531d | ||
|
a8c5c05d37 | ||
|
fdfd1b293c | ||
|
18637a42d9 | ||
|
345469c620 | ||
|
8b01b9c1c1 | ||
|
100acd416f | ||
|
31d5b5878b | ||
|
8c74d1de1c | ||
|
f45c1aa644 | ||
|
87526650a6 | ||
|
6d977f411c | ||
|
9b86dfdb39 | ||
|
485a0dc279 | ||
|
67338051e7 | ||
|
2ed0da8cf0 | ||
|
096c318d4e | ||
|
a0084b1060 | ||
|
8ff7d9460f | ||
|
ca1314c4ac | ||
|
c06343128a | ||
|
bf2303ead8 | ||
|
4b0ac11b82 | ||
|
4f61ac06af | ||
|
a73d1cfc0c | ||
|
a7ed30e2cc | ||
|
1c38a91d41 | ||
|
6d284ad5af | ||
|
9287e47163 | ||
|
03bbf2f040 | ||
|
34db6017e4 | ||
|
5714892115 | ||
|
b0ce5bdc81 | ||
|
7ae85226f7 | ||
|
0a75549663 | ||
|
e62db154a4 | ||
|
3e6bd3ecc5 | ||
|
625b59b17b | ||
|
01f4cb4c6c | ||
|
a6289150c1 | ||
|
82749229a7 | ||
|
fd574ce102 | ||
|
c297869a3c | ||
|
42f6ee09e5 | ||
|
785cf75d60 | ||
|
2ed55b143e | ||
|
0113c61911 | ||
|
c02e4cae7c | ||
|
4568ef238b | ||
|
f570a9cc83 | ||
|
aba7caf3d8 | ||
|
035dfbeed8 | ||
|
bafe448914 | ||
|
d22e2c1105 | ||
|
3bbfa428ea | ||
|
92f1d58026 | ||
|
629e061049 | ||
|
9156552f91 | ||
|
957d6373eb | ||
|
efca378117 | ||
|
ce9a5e2489 | ||
|
98d551f0b2 | ||
|
3668475526 | ||
|
6b4da4a04b | ||
|
d5ae737319 | ||
|
ecd81dfed0 | ||
|
fd7b39eaea | ||
|
136be273ce | ||
|
b80764282a | ||
|
9844fee8c5 | ||
|
aab11fbd94 | ||
|
2dd8f789fc | ||
|
94a6b42a2b | ||
|
ee45f0a829 | ||
|
9da81ee290 | ||
|
c38c7dd2a1 | ||
|
ede0046d4f | ||
|
d4de199501 | ||
|
b6602fc8e3 | ||
|
206bcdf712 | ||
|
75773f62f8 | ||
|
365b440697 | ||
|
f9168cac71 | ||
|
42d655f0f2 | ||
|
59c931d16f | ||
|
29aa605c44 | ||
|
dcf554d8d8 | ||
|
2f4b325a7d | ||
|
4cd5b0aec3 | ||
|
335ff55dd4 | ||
|
cd6e00b326 | ||
|
7f46cc3e91 | ||
|
6b2742b067 | ||
|
237886feb6 | ||
|
e816b2aa80 | ||
|
913a2ffc2d | ||
|
ee19e5c6b5 | ||
|
ced94c88d9 | ||
|
cc6b0bcfd3 | ||
|
1132c90674 | ||
|
ab744aad8f | ||
|
0c7729e783 | ||
|
0874e13824 | ||
|
c4929d51e1 | ||
|
3c363da883 | ||
|
e7c00914dd | ||
|
f5690edc3c | ||
|
c07eacfd6a | ||
|
a23dd1d1e5 | ||
|
3b558e1c2a | ||
|
96b9476d5a | ||
|
8d476a0644 | ||
|
614cde79a0 | ||
|
99b3168452 | ||
|
169e2d7762 | ||
|
63f3357384 | ||
|
30b07077be | ||
|
996b70320e | ||
|
2a8e4034e3 | ||
|
c0ace1e6fb | ||
|
7d24be9653 | ||
|
a4fd1e62aa | ||
|
6956468b64 | ||
|
7bee777362 | ||
|
e504573fea | ||
|
13da0112f2 | ||
|
1e40d6f492 | ||
|
e81a19a04b | ||
|
e9902e2391 | ||
|
fd71ceae82 | ||
|
1a12f48e2e | ||
|
0fa32c7cf9 | ||
|
e564559bda | ||
|
954bc4dde0 | ||
|
fda3e9886e | ||
|
45f147ec24 | ||
|
f2f82c7d03 | ||
|
62a5265433 | ||
|
ef0ce7d669 | ||
|
79e4e9fdea | ||
|
f7976419ae | ||
|
5f150d3ae5 | ||
|
1644a855ee | ||
|
9c8a9d1d1d | ||
|
589f1dbbad | ||
|
a5591d9f54 | ||
|
b4b3c4b0ac | ||
|
a1152aee96 | ||
|
7c5118959d | ||
|
531dddecdc | ||
|
50a96a3f21 | ||
|
a9d6fd3e46 | ||
|
dbe9ae44df | ||
|
4f1d4137d4 | ||
|
1323226677 | ||
|
4857cdbedc | ||
|
6b9074da2a | ||
|
b51030d003 | ||
|
6c88a9f19f | ||
|
5b02adf114 | ||
|
b378396d38 | ||
|
4a63fed224 | ||
|
19f806acd5 | ||
|
e3d5027681 | ||
|
d6693f4346 | ||
|
07d27e0421 | ||
|
02c7b2be87 | ||
|
d7e2d65ff7 | ||
|
5288756d04 | ||
|
f01bc29f57 | ||
|
25185cff4e | ||
|
fb44d4d90d | ||
|
33cf5a1cd5 | ||
|
4f59e2441c | ||
|
3822e77561 | ||
|
40f6e51b06 | ||
|
c6ec5c45d1 | ||
|
aa9a0de6b9 | ||
|
365033ac6a | ||
|
05e480e6d2 | ||
|
9e3ef4869e | ||
|
b866fb74c0 | ||
|
4bd89ffbbd | ||
|
f3dd80d73f | ||
|
0d57d97772 | ||
|
9b6e94d453 | ||
|
f91ec300b0 | ||
|
dcf22f34bb | ||
|
bea563dab9 | ||
|
8d73dd6cd7 | ||
|
87276357ce | ||
|
dfd2110776 | ||
|
bad913c806 | ||
|
2e480340de | ||
|
411b3280d1 | ||
|
a1e360522c | ||
|
a08289d78c | ||
|
1cce03de28 | ||
|
2066533467 | ||
|
5d492fad9b | ||
|
5a3f2bcfb9 | ||
|
4bf90735ef |
18
.gitignore
vendored
18
.gitignore
vendored
@@ -166,6 +166,12 @@ UpgradeLog*.htm
|
||||
App_Data/*.mdf
|
||||
App_Data/*.ldf
|
||||
|
||||
#################
|
||||
## Other ide stuff
|
||||
#################
|
||||
.idea/*
|
||||
[#]*[#]
|
||||
|
||||
#############
|
||||
## Windows detritus
|
||||
#############
|
||||
@@ -214,3 +220,15 @@ pip-log.txt
|
||||
|
||||
#Mr Developer
|
||||
.mr.developer.cfg
|
||||
|
||||
##############
|
||||
## RSS-Bridge
|
||||
##############
|
||||
/cache
|
||||
/whitelist.txt
|
||||
DEBUG
|
||||
|
||||
######################
|
||||
## VisualStudioCode ##
|
||||
######################
|
||||
.vscode/*
|
19
.travis.yml
Normal file
19
.travis.yml
Normal file
@@ -0,0 +1,19 @@
|
||||
language: php
|
||||
php:
|
||||
- '5.6'
|
||||
- '7.0'
|
||||
- hhvm
|
||||
- nightly
|
||||
|
||||
install:
|
||||
- pear install PHP_CodeSniffer
|
||||
|
||||
script:
|
||||
- phpenv rehash
|
||||
- phpcs . --standard=phpcs.xml --warning-severity=0 --extensions=php -p
|
||||
|
||||
matrix:
|
||||
fast_finish: true
|
||||
allow_failures:
|
||||
- php: hhvm
|
||||
- php: nightly
|
163
CHANGELOG.md
Normal file
163
CHANGELOG.md
Normal file
@@ -0,0 +1,163 @@
|
||||
rss-bridge Changelog
|
||||
===
|
||||
|
||||
Alpha 0.1
|
||||
===
|
||||
* First tagged version.
|
||||
* Includes refactoring.
|
||||
* Unstable.
|
||||
|
||||
Alpha 0.2
|
||||
===
|
||||
|
||||
## Important changes
|
||||
* RSS-Bridge has been [UNLICENSED](UNLICENSE)
|
||||
* RSS-Bridge is now a community-managed project on [GitHub](https://github.com/rss-bridge/rss-bridge)
|
||||
* RSS-Bridge now has a [Wiki](https://github.com/rss-bridge/rss-bridge/wiki)
|
||||
* RSS-Bridge now supports [Travis-CI](https://travis-ci.org)
|
||||
|
||||
## General changes
|
||||
* Added [CHANGELOG](CHANGELOG.md) (this file)
|
||||
* Added [PHP Simple HTML DOM Parser](http://simplehtmldom.sourceforge.net) to [vendor](vendor/simplehtmldom/)
|
||||
* Added cache purging function (cache will be force-purged after 24 hours or as defined by bridge)
|
||||
* Added new format [MrssFormat](formats/MrssFormat.php)
|
||||
* Added parameter `author` - for display of the feed author name - to all formats
|
||||
* Added new abstraction of the BridgeInterface:
|
||||
- [FeedExpander](https://github.com/RSS-Bridge/rss-bridge/wiki/Bridge-API)
|
||||
* Added optional support for proxy usage on each individual bridge
|
||||
* Added support for [custom bridge parameter](https://github.com/RSS-Bridge/rss-bridge/wiki/BridgeAbstract#format-specifications) (text, number, list, checkbox)
|
||||
* Changed design of the welcome screen
|
||||
* Changed design of HtmlFormat
|
||||
* Changed behavior of debug mode:
|
||||
- Enable debug mode by placing a file called "DEBUG" in the root folder
|
||||
- Debug mode automatically disables cache file loading
|
||||
* Changed implementation of bridges - see [Wiki](https://github.com/rss-bridge/rss-bridge/wiki)
|
||||
- Changed comment-style metadata to constants
|
||||
- Added support for multiple utilizations per bridge
|
||||
- Changed the parameter loading algorithm to be loaded by RSS-Bridge core
|
||||
* Improved checks for PHP version, configuration and extensions
|
||||
* Many bug fixes
|
||||
|
||||
## Modified Bridges
|
||||
* FlickrExploreBridge
|
||||
* GoogleSearchBridge
|
||||
* TwitterBridge
|
||||
|
||||
## New Bridges
|
||||
* ABCTabsBridge
|
||||
* AcrimedBridge
|
||||
* AllocineFRBridge
|
||||
* AnimeUltimeBridge
|
||||
* Arte7Bridge
|
||||
* AskfmBridge
|
||||
* BandcampBridge
|
||||
* BastaBridge
|
||||
* BlaguesDeMerdeBridge
|
||||
* BooruprojectBridge
|
||||
* CADBridge
|
||||
* CNETBridge
|
||||
* CastorusBridge
|
||||
* CollegeDeFranceBridge
|
||||
* CommonDreamsBridge
|
||||
* CopieDoubleBridge
|
||||
* CourrierInternationalBridge
|
||||
* CpasbienBridge
|
||||
* CryptomeBridge
|
||||
* DailymotionBridge
|
||||
* DanbooruBridge
|
||||
* DansTonChatBridge
|
||||
* DauphineLibereBridge
|
||||
* DemoBridge
|
||||
* DeveloppezDotComBridge
|
||||
* DilbertBridge
|
||||
* DollbooruBridge
|
||||
* DuckDuckGoBridge
|
||||
* EZTVBridge
|
||||
* EliteDangerousGalnetBridge
|
||||
* ElsevierBridge
|
||||
* EstCeQuonMetEnProdBridge
|
||||
* FacebookBridge
|
||||
* FierPandaBridge
|
||||
* FlickrTagBridge
|
||||
* FootitoBridge
|
||||
* FourchanBridge
|
||||
* FuturaSciencesBridge
|
||||
* GBAtempBridge
|
||||
* GelbooruBridge
|
||||
* GiphyBridge
|
||||
* GithubIssueBridge
|
||||
* GizmodoBridge
|
||||
* GooglePlusPostBridge
|
||||
* HDWallpapersBridge
|
||||
* HentaiHavenBridge
|
||||
* IdenticaBridge
|
||||
* InstagramBridge
|
||||
* IsoHuntBridge
|
||||
* JapanExpoBridge
|
||||
* KonachanBridge
|
||||
* KoreusBridge
|
||||
* KununuBridge
|
||||
* LWNprevBridge
|
||||
* LeBonCoinBridge
|
||||
* LegifranceJOBridge
|
||||
* LeMondeInformatiqueBridge
|
||||
* LesJoiesDuCodeBridge
|
||||
* LichessBridge
|
||||
* LinkedInCompanyBridge
|
||||
* LolibooruBridge
|
||||
* MangareaderBridge
|
||||
* MilbooruBridge
|
||||
* MoebooruBridge
|
||||
* MondeDiploBridge
|
||||
* MsnMondeBridge
|
||||
* MspabooruBridge
|
||||
* NasaApodBridge
|
||||
* NeuviemeArtBridge
|
||||
* NextInpactBridge
|
||||
* NextgovBridge
|
||||
* NiceMatinBridge
|
||||
* NovelUpdatesBridge
|
||||
* OpenClassroomsBridge
|
||||
* ParuVenduImmoBridge
|
||||
* PickyWallpapersBridge
|
||||
* PinterestBridge
|
||||
* PlanetLibreBridge
|
||||
* RTBFBridge
|
||||
* ReadComicsBridge
|
||||
* Releases3DSBridge
|
||||
* ReporterreBridge
|
||||
* Rue89Bridge
|
||||
* Rule34Bridge
|
||||
* Rule34pahealBridge
|
||||
* SafebooruBridge
|
||||
* SakugabooruBridge
|
||||
* ScmbBridge
|
||||
* ScoopItBridge
|
||||
* SensCritiqueBridge
|
||||
* SexactuBridge
|
||||
* ShanaprojectBridge
|
||||
* Shimmie2Bridge
|
||||
* SoundcloudBridge
|
||||
* StripeAPIChangeLogBridge
|
||||
* SuperbWallpapersBridge
|
||||
* T411Bridge
|
||||
* TagBoardBridge
|
||||
* TbibBridge
|
||||
* TheCodingLoveBridge
|
||||
* TheHackerNewsBridge
|
||||
* ThePirateBayBridge
|
||||
* UnsplashBridge
|
||||
* ViadeoCompanyBridge
|
||||
* VineBridge
|
||||
* VkBridge
|
||||
* WallpaperStopBridge
|
||||
* WebfailBridge
|
||||
* WeLiveSecurityBridge
|
||||
* WhydBridge
|
||||
* WikipediaBridge
|
||||
* WordPressBridge
|
||||
* WorldOfTanksBridge
|
||||
* XbooruBridge
|
||||
* YandereBridge
|
||||
* YoutubeBridge
|
||||
* ZDNetBridge
|
136
README.md
136
README.md
@@ -1,74 +1,142 @@
|
||||
rss-bridge
|
||||
===
|
||||
[](UNLICENSE)
|
||||
|
||||
Version alpha 0.1
|
||||
rss-bridge is a PHP project capable of generating ATOM feeds for websites which don't have one.
|
||||
|
||||
rss-bridge is a collection of independant php scripts capable of generating ATOM feed for specific pages which don't have one.
|
||||
|
||||
Supported sites/pages
|
||||
Supported sites/pages (main)
|
||||
===
|
||||
|
||||
* `FlickrExplore` : [Latest interesting images](http://www.flickr.com/explore) from Flickr.
|
||||
* `GoogleSearch` : Most recent results from Google Search. Parameters:
|
||||
* q=keyword : Keyword search.
|
||||
* `Twitter` : Twitter. Parameters:
|
||||
* q=keyword : Keyword search.
|
||||
* u=username : Get user timeline.
|
||||
* `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
|
||||
* `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/)
|
||||
* `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/)
|
||||
|
||||
Easy new bridge system (detail below) !
|
||||
Plus [many other bridges](bridges/) to enable, thanks to the community
|
||||
|
||||
Output format
|
||||
===
|
||||
Output format can be used in any rss-bridge:
|
||||
Output format can take several forms:
|
||||
|
||||
* `Atom` : ATOM Feed.
|
||||
* `Json` : Json
|
||||
* `Html` : html page
|
||||
* `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.
|
||||
* `Plaintext` : raw text (php object, as returned by print_r)
|
||||
|
||||
Screenshot
|
||||
===
|
||||
|
||||

|
||||
Welcome screen:
|
||||
|
||||

|
||||
|
||||
RSS-Bridge hashtag (#rss-bridge) search on Twitter, in ATOM format (as displayed by Firefox):
|
||||
|
||||

|
||||
|
||||
Requirements
|
||||
===
|
||||
|
||||
* php 5.3
|
||||
* [PHP Simple HTML DOM Parser](http://simplehtmldom.sourceforge.net). (Put `simple_html_dom.php` in `vendor/simplehtmldom`).
|
||||
* Ssl lib activated in PHP config
|
||||
* PHP 5.6, e.g. `AddHandler application/x-httpd-php56 .php` in `.htaccess`
|
||||
* `openssl` extension enabled in PHP config (`php.ini`)
|
||||
* `allow_url_fopen=1` in `php.ini`
|
||||
|
||||
|
||||
Author
|
||||
Enabling/Disabling bridges
|
||||
===
|
||||
I'm sebsauvage, webmaster of [sebsauvage.net](http://sebsauvage.net), author of [Shaarli](http://sebsauvage.net/wiki/doku.php?id=php:shaarli) and [ZeroBin](http://sebsauvage.net/wiki/doku.php?id=php:zerobin).
|
||||
|
||||
Thanks to [Mitsukarenai](https://github.com/Mitsukarenai) for the inspiration.
|
||||
By default, the script creates `whitelist.txt` and adds the main bridges (see above). `whitelist.txt` is ignored by git, you can edit it:
|
||||
* to enable extra bridges (one bridge per line)
|
||||
* to disable main bridges (remove the line)
|
||||
* to enable all bridges (just one wildcard `*` as file content)
|
||||
|
||||
Patch :
|
||||
- Yves ASTIER (Draeli) : PHP optimizations, fixes, dynamic brigde/format list with all stuff behind and extend cache system. Mail : contact@yves-astier.com
|
||||
New bridges are disabled by default, so make sure to check regularly what's new and whitelist what you want!
|
||||
|
||||
Licence
|
||||
Deploy
|
||||
===
|
||||
Code is public domain.
|
||||
[](https://my.scalingo.com/deploy?source=https://github.com/sebsauvage/rss-bridge)
|
||||
|
||||
Authors
|
||||
===
|
||||
We are RSS Bridge Community, a group of developers continuing the project initiated by sebsauvage, webmaster of [sebsauvage.net](http://sebsauvage.net), author of [Shaarli](http://sebsauvage.net/wiki/doku.php?id=php:shaarli) and [ZeroBin](http://sebsauvage.net/wiki/doku.php?id=php:zerobin).
|
||||
|
||||
Patch/contributors :
|
||||
|
||||
* Yves ASTIER ([Draeli](https://github.com/Draeli)) : PHP optimizations, fixes, dynamic brigde/format list with all stuff behind and extend cache system. Mail : contact /at\ yves-astier.com
|
||||
* [Mitsukarenai](https://github.com/Mitsukarenai) : Initial inspiration, collaborator
|
||||
* [ArthurHoaro](https://github.com/ArthurHoaro)
|
||||
* [BoboTiG](https://github.com/BoboTiG)
|
||||
* [Astalaseven](https://github.com/Astalaseven)
|
||||
* [qwertygc](https://github.com/qwertygc)
|
||||
* [Djuuu](https://github.com/Djuuu)
|
||||
* [Anadrark](https://github.com/Anadrark])
|
||||
* [Grummfy](https://github.com/Grummfy)
|
||||
* [Polopollo](https://github.com/Polopollo)
|
||||
* [16mhz](https://github.com/16mhz)
|
||||
* [kranack](https://github.com/kranack)
|
||||
* [logmanoriginal](https://github.com/logmanoriginal)
|
||||
* [polo2ro](https://github.com/polo2ro)
|
||||
* [Riduidel](https://github.com/Riduidel)
|
||||
* [superbaillot.net](http://superbaillot.net/)
|
||||
* [vinzv](https://github.com/vinzv)
|
||||
* [teromene](https://github.com/teromene)
|
||||
* [nel50n](https://github.com/nel50n)
|
||||
* [nyutag](https://github.com/nyutag)
|
||||
* [ORelio](https://github.com/ORelio)
|
||||
* [Pitchoule](https://github.com/Pitchoule)
|
||||
* [pit-fgfjiudghdf](https://github.com/pit-fgfjiudghdf)
|
||||
* [aledeg](https://github.com/aledeg)
|
||||
* [alexAubin](https://github.com/alexAubin)
|
||||
* [cnlpete](https://github.com/cnlpete)
|
||||
* [corenting](https://github.com/corenting)
|
||||
* [Daiyousei](https://github.com/Daiyousei)
|
||||
* [erwang](https://github.com/erwang)
|
||||
* [gsurrel](https://github.com/gsurrel)
|
||||
* [kraoc](https://github.com/kraoc)
|
||||
* [lagaisse](https://github.com/lagaisse)
|
||||
* [az5he6ch](https://github.com/az5he6ch)
|
||||
* [niawag](https://github.com/niawag)
|
||||
* [JeremyRand](https://github.com/JeremyRand)
|
||||
* [mro](https://github.com/mro)
|
||||
|
||||
Licenses
|
||||
===
|
||||
Code is [Public Domain](UNLICENSE).
|
||||
|
||||
Including `PHP Simple HTML DOM Parser` under the [MIT License](http://opensource.org/licenses/MIT)
|
||||
|
||||
|
||||
Technical notes
|
||||
===
|
||||
* There is a cache so that source services won't ban you even if you hammer the rss-bridge with requests. Each bridge has a different duration for the cache. The `cache` subdirectory will be automatically created. You can purge it whenever you want.
|
||||
* To implement a new rss-bridge, create a new class in `bridges` directory and extends with `BridgeAbstract`. Look at existing bridges for examples. For items you generate in `$this->items`, only `uri` and `title` are mandatory in each item. `timestamp` and `content` are optional but recommended. Any additional key will be ignored by ATOM feed (but outputed to jSon). If you want your new bridge appear in `index.php`, don't forget add annotation.
|
||||
* There is a cache so that source services won't ban you even if you hammer the rss-bridge with requests. Each bridge can have a different duration for the cache. The `cache` subdirectory will be automatically created and cached objects older than 24 hours get purged.
|
||||
* To implement a new Bridge, [follow the specifications](https://github.com/RSS-Bridge/rss-bridge/wiki/Bridge-API) and take a look at existing Bridges for examples.
|
||||
* To enable debug mode (disabling cache and enabling error reporting), create an empty file named `DEBUG` in the root directory (next to `index.php`).
|
||||
* For more information refer to the [Wiki](https://github.com/RSS-Bridge/rss-bridge/wiki)
|
||||
|
||||
Rant
|
||||
===
|
||||
|
||||
*Dear so-called "social" websites.*
|
||||
|
||||
Your catchword is <EFBFBD>share<EFBFBD>, but you don't want us to share. You want to keep us within your walled gardens. That's why you've been removing RSS links from webpages, hiding them deep on your website, or removed RSS entirely, replacing it with crippled or demented proprietary API. **FUCK YOU.**
|
||||
Your catchword is "share", but you don't want us to share. You want to keep us within your walled gardens. That's why you've been removing RSS links from webpages, hiding them deep on your website, or removed feeds entirely, replacing it with crippled or demented proprietary API. **FUCK YOU.**
|
||||
|
||||
You're not social when you hamper sharing by removing RSS. You're happy to have customers create content for your ecosystem, but you don't want this content out - a content you do not even own. Google Takeout is just a gimmick. We want our data to flow, we want RSS.
|
||||
You're not social when you hamper sharing by removing feeds. You're happy to have customers creating content for your ecosystem, but you don't want this content out - a content you do not even own. Google Takeout is just a gimmick. We want our data to flow, we want RSS or ATOM feeds.
|
||||
|
||||
We want to share with friends, using open protocols: RSS, XMPP, whatever. Because no one wants to have *your* service with *your* applications using *your* API forced-feeded to them. Friends must be free to choose whatever software and service they want.
|
||||
We want to share with friends, using open protocols: RSS, ATOM, XMPP, whatever. Because no one wants to have *your* service with *your* applications using *your* API force-feeding them. Friends must be free to choose whatever software and service they want.
|
||||
|
||||
We are rebuilding bridges your have wilfully destroyed.
|
||||
We are rebuilding bridges you have wilfully destroyed.
|
||||
|
||||
Get your shit together: Put RSS back in.
|
||||
Get your shit together: Put RSS/ATOM back in.
|
||||
|
25
UNLICENSE
Normal file
25
UNLICENSE
Normal file
@@ -0,0 +1,25 @@
|
||||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
For more information, please refer to <http://unlicense.org>
|
||||
|
25
bridges/ABCTabsBridge.php
Normal file
25
bridges/ABCTabsBridge.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?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";
|
||||
|
||||
public function collectData(){
|
||||
$html = '';
|
||||
$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)
|
||||
{
|
||||
$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');
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
}
|
25
bridges/AcrimedBridge.php
Normal file
25
bridges/AcrimedBridge.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
class AcrimedBridge extends FeedExpander {
|
||||
|
||||
const MAINTAINER = "qwertygc";
|
||||
const NAME = "Acrimed Bridge";
|
||||
const URI = "http://www.acrimed.org/";
|
||||
const CACHE_TIMEOUT = 4800; //2hours
|
||||
const DESCRIPTION = "Returns the newest articles.";
|
||||
|
||||
public function collectData(){
|
||||
$this->collectExpandableDatas(static::URI.'spip.php?page=backend');
|
||||
}
|
||||
|
||||
protected function parseItem($newsItem){
|
||||
$item = parent::parseItem($newsItem);
|
||||
|
||||
$articlePage = getSimpleHTMLDOM($newsItem->link);
|
||||
$article = sanitize($articlePage->find('article.article1', 0)->innertext);
|
||||
$article = defaultImageSrcTo($article, static::URI);
|
||||
$item['content'] = $article;
|
||||
|
||||
return $item;
|
||||
}
|
||||
|
||||
}
|
82
bridges/AllocineFRBridge.php
Normal file
82
bridges/AllocineFRBridge.php
Normal file
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
class AllocineFRBridge extends BridgeAbstract{
|
||||
|
||||
|
||||
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 PARAMETERS = array( array(
|
||||
'category'=>array(
|
||||
'name'=>'category',
|
||||
'type'=>'list',
|
||||
'required'=>true,
|
||||
'exampleValue'=>'Faux Raccord',
|
||||
'title'=>'Select your category',
|
||||
'values'=>array(
|
||||
'Faux Raccord'=>'faux-raccord',
|
||||
'Top 5'=>'top-5',
|
||||
'Tueurs en Séries'=>'tueurs-en-serie'
|
||||
)
|
||||
)
|
||||
));
|
||||
|
||||
public function getURI(){
|
||||
switch($this->getInput('category')){
|
||||
case 'faux-raccord':
|
||||
$uri = static::URI.'video/programme-12284/saison-27129/';
|
||||
break;
|
||||
case 'top-5':
|
||||
$uri = static::URI.'video/programme-12299/saison-29561/';
|
||||
break;
|
||||
case 'tueurs-en-serie':
|
||||
$uri = static::URI.'video/programme-12286/saison-22938/';
|
||||
break;
|
||||
}
|
||||
|
||||
return $uri;
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return self::NAME.' : '
|
||||
.array_search(
|
||||
$this->getInput('category'),
|
||||
self::PARAMETERS[$this->queriedContext]['category']['values']
|
||||
);
|
||||
}
|
||||
|
||||
public function collectData(){
|
||||
|
||||
$html = getSimpleHTMLDOM($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)
|
||||
{
|
||||
$item = array();
|
||||
|
||||
$title = $element->find('div.titlebar h3.title a', 0);
|
||||
$content = trim($element->innertext);
|
||||
$figCaption = strpos($content, $category);
|
||||
|
||||
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);
|
||||
$content = str_replace('href=\'/', 'href=\''.static::URI, $content);
|
||||
$item['content'] = $content;
|
||||
$item['title'] = trim($title->innertext);
|
||||
$item['uri'] = static::URI . $title->href;
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
119
bridges/AnimeUltimeBridge.php
Normal file
119
bridges/AnimeUltimeBridge.php
Normal file
@@ -0,0 +1,119 @@
|
||||
<?php
|
||||
class AnimeUltimeBridge extends BridgeAbstract {
|
||||
|
||||
const MAINTAINER = 'ORelio';
|
||||
const NAME = 'Anime-Ultime';
|
||||
const URI = 'http://www.anime-ultime.net/';
|
||||
const CACHE_TIMEOUT = 10800; // 3h
|
||||
const DESCRIPTION = 'Returns the 10 newest releases posted on Anime-Ultime';
|
||||
const PARAMETERS = array( array(
|
||||
'type'=>array(
|
||||
'name'=>'Type',
|
||||
'type'=>'list',
|
||||
'values'=>array(
|
||||
'Everything'=>'',
|
||||
'Anime'=>'A',
|
||||
'Drama'=>'D',
|
||||
'Tokusatsu'=>'T'
|
||||
)
|
||||
)
|
||||
));
|
||||
|
||||
private $filter = 'Releases';
|
||||
|
||||
public function collectData(){
|
||||
|
||||
//Add type filter if provided
|
||||
$typeFilter = array_search(
|
||||
$this->getInput('type'),
|
||||
self::PARAMETERS[$this->queriedContext]['type']['values']
|
||||
);
|
||||
|
||||
//Build date and filters for making requests
|
||||
$thismonth = date('mY').$typeFilter;
|
||||
$lastmonth = date('mY', mktime(0, 0, 0, date('n') - 1, 1, date('Y'))).$typeFilter;
|
||||
|
||||
//Process each HTML page until having 10 releases
|
||||
$processedOK = 0;
|
||||
foreach (array($thismonth, $lastmonth) as $requestFilter) {
|
||||
|
||||
//Retrive page contents
|
||||
$url = self::URI.'history-0-1/'.$requestFilter;
|
||||
$html = getSimpleHTMLDOM($url)
|
||||
or returnServerError('Could not request Anime-Ultime: '.$url);
|
||||
|
||||
//Relases are sorted by day : process each day individually
|
||||
foreach ($html->find('div.history', 0)->find('h3') as $daySection) {
|
||||
|
||||
//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).'-'
|
||||
.substr($requestFilter, 2, 4));
|
||||
$release = $daySection->next_sibling()->next_sibling()->first_child(); //<h3>day</h3><br /><table><tr> <-- useful data in table rows
|
||||
|
||||
//Process each release of that day, ignoring first table row: contains table headers
|
||||
while (!is_null($release = $release->next_sibling())) {
|
||||
if (count($release->find('td')) > 0) {
|
||||
|
||||
//Retrieve metadata from table columns
|
||||
$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_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
|
||||
$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
|
||||
);
|
||||
$item_description = substr($item_description,
|
||||
0,
|
||||
strpos($item_description, '<div id="table">')
|
||||
);
|
||||
$item_description = str_replace(
|
||||
'src="images', 'src="'.self::URI.'images',
|
||||
$item_description
|
||||
);
|
||||
$item_description = str_replace("\r", '', $item_description);
|
||||
$item_description = str_replace("\n", '', $item_description);
|
||||
$item_description = utf8_encode($item_description);
|
||||
|
||||
//Build and add final item
|
||||
$item = array();
|
||||
$item['uri'] = $item_uri;
|
||||
$item['title'] = $item_name.' '.$item_type.' '.$item_episode;
|
||||
$item['author'] = $item_fansub;
|
||||
$item['timestamp'] = $item_date;
|
||||
$item['content'] = $item_description;
|
||||
$this->items[] = $item;
|
||||
$processedOK++;
|
||||
|
||||
//Stop processing once limit is reached
|
||||
if ($processedOK >= 10)
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getName() {
|
||||
$typeFilter = array_search(
|
||||
$this->getInput('type'),
|
||||
self::PARAMETERS[$this->queriedContext]['type']['values']
|
||||
);
|
||||
|
||||
return 'Latest '.$typeFilter.' - Anime-Ultime Bridge';
|
||||
}
|
||||
|
||||
}
|
91
bridges/Arte7Bridge.php
Normal file
91
bridges/Arte7Bridge.php
Normal file
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
class Arte7Bridge extends BridgeAbstract{
|
||||
|
||||
const MAINTAINER = "mitsukarenai";
|
||||
const NAME = "Arte +7";
|
||||
const URI = "http://www.arte.tv/";
|
||||
const CACHE_TIMEOUT = 1800; // 30min
|
||||
const DESCRIPTION = "Returns newest videos from ARTE +7";
|
||||
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'
|
||||
|
||||
)
|
||||
)
|
||||
),
|
||||
'Catégorie (Allemand)' => array(
|
||||
'catde'=>array(
|
||||
'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'
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
public function collectData(){
|
||||
|
||||
switch($this->queriedContext){
|
||||
case 'Catégorie (Français)':
|
||||
$category=$this->getInput('catfr');
|
||||
$lang='fr';
|
||||
break;
|
||||
case 'Catégorie (Allemand)':
|
||||
$category=$this->getInput('catde');
|
||||
$lang='de';
|
||||
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].'}]}';
|
||||
}
|
||||
|
||||
$input_json = json_decode(html_entity_decode($input, ENT_QUOTES), TRUE);
|
||||
|
||||
foreach($input_json['videos'] as $element) {
|
||||
$item = array();
|
||||
$item['uri'] = str_replace("autoplay=1", "", $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['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>';
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
52
bridges/AskfmBridge.php
Normal file
52
bridges/AskfmBridge.php
Normal file
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
class AskfmBridge extends BridgeAbstract{
|
||||
|
||||
const MAINTAINER = "az5he6ch";
|
||||
const NAME = "Ask.fm Answers";
|
||||
const URI = "http://ask.fm/";
|
||||
const CACHE_TIMEOUT = 300; //5 min
|
||||
const DESCRIPTION = "Returns answers from an Ask.fm user";
|
||||
const PARAMETERS = array(
|
||||
'Ask.fm username'=>array(
|
||||
'u'=>array(
|
||||
'name'=>'Username',
|
||||
'required'=>true
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
public function collectData(){
|
||||
$html = getSimpleHTMLDOM($this->getURI())
|
||||
or returnServerError('Requested username can\'t be found.');
|
||||
|
||||
foreach($html->find('div.streamItem-answer') as $element) {
|
||||
$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));
|
||||
$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
|
||||
//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
|
||||
$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);
|
||||
$item['content'] = $content;
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return self::NAME.' : '.$this->getInput('u');
|
||||
}
|
||||
|
||||
public function getURI(){
|
||||
return self::URI.urlencode($this->getInput('u')).'/answers/more?page=0';
|
||||
}
|
||||
}
|
43
bridges/BandcampBridge.php
Normal file
43
bridges/BandcampBridge.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
class BandcampBridge extends BridgeAbstract{
|
||||
|
||||
const MAINTAINER = "sebsauvage";
|
||||
const NAME = "Bandcamp Tag";
|
||||
const URI = "http://bandcamp.com/";
|
||||
const CACHE_TIMEOUT = 600; // 10min
|
||||
const DESCRIPTION = "New bandcamp release by tag";
|
||||
const PARAMETERS = array( array(
|
||||
'tag'=>array(
|
||||
'name'=>'tag',
|
||||
'type'=>'text',
|
||||
'required'=>true
|
||||
)
|
||||
));
|
||||
|
||||
public function collectData(){
|
||||
$html = getSimpleHTMLDOM($this->getURI())
|
||||
or returnServerError('No results for this query.');
|
||||
|
||||
foreach($html->find('li.item') as $release) {
|
||||
$script = $release->find('div.art', 0)->getAttribute('onclick');
|
||||
$uri = ltrim($script, "return 'url(");
|
||||
$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['id'] = $release->find('a',0)->getAttribute('href');
|
||||
$item['uri'] = $release->find('a',0)->getAttribute('href');
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
public function getURI(){
|
||||
return self::URI.'tag/'.urlencode($this->getInput('tag')).'?sort_field=date';
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return $this->getInput('tag') .' - '.'Bandcamp Tag';
|
||||
}
|
||||
}
|
32
bridges/BastaBridge.php
Normal file
32
bridges/BastaBridge.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
class BastaBridge extends BridgeAbstract{
|
||||
const MAINTAINER = "qwertygc";
|
||||
const NAME = "Bastamag Bridge";
|
||||
const URI = "http://www.bastamag.net/";
|
||||
const CACHE_TIMEOUT = 7200; // 2h
|
||||
const DESCRIPTION = "Returns the newest articles.";
|
||||
|
||||
public function collectData(){
|
||||
// Replaces all relative image URLs by absolute URLs. Relative URLs always start with 'local/'!
|
||||
function ReplaceImageUrl($content){
|
||||
return preg_replace('/src=["\']{1}([^"\']+)/ims', 'src=\''.self::URI.'$1\'', $content);
|
||||
}
|
||||
|
||||
$html = getSimpleHTMLDOM(self::URI.'spip.php?page=backend')
|
||||
or returnServerError('Could not request Bastamag.');
|
||||
$limit = 0;
|
||||
|
||||
foreach($html->find('item') as $element) {
|
||||
if($limit < 10) {
|
||||
$item = array();
|
||||
$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);
|
||||
$this->items[] = $item;
|
||||
$limit++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
33
bridges/BlaguesDeMerdeBridge.php
Normal file
33
bridges/BlaguesDeMerdeBridge.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
class BlaguesDeMerdeBridge extends BridgeAbstract{
|
||||
|
||||
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";
|
||||
|
||||
|
||||
public function collectData(){
|
||||
$html = getSimpleHTMLDOM(self::URI)
|
||||
or returnServerError('Could not request BDM.');
|
||||
|
||||
foreach($html->find('article.joke_contener') as $element) {
|
||||
$item = array();
|
||||
$temp = $element->find('a');
|
||||
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;
|
||||
$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;;
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
36
bridges/BooruprojectBridge.php
Normal file
36
bridges/BooruprojectBridge.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
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 PARAMETERS = array(
|
||||
'global'=>array(
|
||||
'p'=>array(
|
||||
'name'=>'page',
|
||||
'type'=>'number'
|
||||
),
|
||||
't'=>array('name'=>'tags')
|
||||
),
|
||||
'Booru subdomain (subdomain.booru.org)'=>array(
|
||||
'i'=>array(
|
||||
'name'=>'Subdomain',
|
||||
'required'=>true
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
const PIDBYPAGE=20;
|
||||
|
||||
public function getURI(){
|
||||
return 'http://'.$this->getInput('i').'.booru.org/';
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return static::NAME . ' ' . $this->getInput('i');
|
||||
}
|
||||
}
|
46
bridges/CADBridge.php
Normal file
46
bridges/CADBridge.php
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
class CADBridge extends FeedExpander {
|
||||
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.";
|
||||
|
||||
public function collectData(){
|
||||
$this->collectExpandableDatas('http://cdn2.cad-comic.com/rss.xml', 10);
|
||||
}
|
||||
|
||||
protected function parseItem($newsItem){
|
||||
$item = parent::parseItem($newsItem);
|
||||
$item['content'] = $this->CADExtractContent($item['uri']);
|
||||
return $item;
|
||||
}
|
||||
|
||||
private function CADExtractContent($url) {
|
||||
$html3 = getSimpleHTMLDOMCached($url);
|
||||
|
||||
// The request might fail due to missing https support or wrong URL
|
||||
if($html3 == false)
|
||||
return 'Daily comic not released yet';
|
||||
|
||||
$htmlpart = explode("/", $url);
|
||||
|
||||
switch ($htmlpart[3]){
|
||||
case 'cad':
|
||||
preg_match_all("/http:\/\/cdn2\.cad-comic\.com\/comics\/cad-\S*png/", $html3, $url2);
|
||||
break;
|
||||
case 'sillies':
|
||||
preg_match_all("/http:\/\/cdn2\.cad-comic\.com\/comics\/sillies-\S*gif/", $html3, $url2);
|
||||
break;
|
||||
default:
|
||||
return 'Daily comic not released yet';
|
||||
}
|
||||
$img = implode ($url2[0]);
|
||||
$html3->clear();
|
||||
unset ($html3);
|
||||
if ($img == '')
|
||||
return 'Daily comic not released yet';
|
||||
return '<img src="'.$img.'"/>';
|
||||
}
|
||||
}
|
||||
?>
|
76
bridges/CNETBridge.php
Normal file
76
bridges/CNETBridge.php
Normal file
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
class CNETBridge extends BridgeAbstract {
|
||||
|
||||
const MAINTAINER = 'ORelio';
|
||||
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 PARAMETERS = array( array(
|
||||
'topic'=>array('name'=>'Topic name')
|
||||
));
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 = '<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>');
|
||||
return $article_html;
|
||||
}
|
||||
|
||||
$pageUrl = self::URI.(empty($this->getInput('topic')) ? '' : 'topics/'.$this->getInput('topic').'/');
|
||||
$html = getSimpleHTMLDOM($pageUrl) or returnServerError('Could not request CNET: '.$pageUrl);
|
||||
$limit = 0;
|
||||
|
||||
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>')));
|
||||
|
||||
$item = array();
|
||||
$item['uri'] = $article_uri;
|
||||
$item['title'] = $article_title;
|
||||
$item['author'] = $article_author;
|
||||
$item['timestamp'] = $article_timestamp;
|
||||
$item['content'] = $article_content;
|
||||
$this->items[] = $item;
|
||||
$limit++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getName() {
|
||||
$topic=$this->getInput('topic');
|
||||
return 'CNET News Bridge'.(empty($topic) ? '' : ' - '.$topic);
|
||||
}
|
||||
}
|
111
bridges/CastorusBridge.php
Normal file
111
bridges/CastorusBridge.php
Normal file
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
class CastorusBridge extends BridgeAbstract {
|
||||
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 PARAMETERS = array(
|
||||
'Get latest changes' => array(),
|
||||
'Get latest changes via ZIP code' => array(
|
||||
'zip'=>array(
|
||||
'name'=>'ZIP code',
|
||||
'type'=>'text',
|
||||
'required'=>true,
|
||||
'exampleValue'=>'74910, 74',
|
||||
'title'=>'Insert ZIP code (complete or partial)'
|
||||
)
|
||||
),
|
||||
'Get latest changes via city name' => array(
|
||||
'city'=>array(
|
||||
'name'=>'City name',
|
||||
'type'=>'text',
|
||||
'required'=>true,
|
||||
'exampleValue'=>'Seyssel, Seys',
|
||||
'title'=>'Insert city name (complete or partial)'
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
// Extracts the tile from an actitiy
|
||||
private function ExtractActivityTitle($activity){
|
||||
$title = $activity->find('a', 0);
|
||||
|
||||
if(!$title)
|
||||
returnServerError('Cannot find title!');
|
||||
|
||||
return htmlspecialchars(trim($title->plaintext));
|
||||
}
|
||||
|
||||
// Extracts the url from an actitiy
|
||||
private function ExtractActivityUrl($activity){
|
||||
$url = $activity->find('a', 0);
|
||||
|
||||
if(!$url)
|
||||
returnServerError('Cannot find url!');
|
||||
|
||||
return self::URI . $url->href;
|
||||
}
|
||||
|
||||
// Extracts the time from an 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('*');
|
||||
|
||||
if(!$nodes)
|
||||
returnServerError('Cannot find nodes!');
|
||||
|
||||
foreach($nodes as $node){
|
||||
$node->outertext = '';
|
||||
}
|
||||
|
||||
return strtotime($activity->innertext);
|
||||
}
|
||||
|
||||
// Extracts the price change
|
||||
private function ExtractActivityPrice($activity){
|
||||
$price = $activity->find('span', 1);
|
||||
|
||||
if(!$price)
|
||||
returnServerError('Cannot find price!');
|
||||
|
||||
return $price->innertext;
|
||||
}
|
||||
|
||||
public function collectData(){
|
||||
$zip_filter = trim($this->getInput('zip'));
|
||||
$city_filter = trim($this->getInput('city'));
|
||||
|
||||
$html = getSimpleHTMLDOM(self::URI);
|
||||
|
||||
if(!$html)
|
||||
returnServerError('Could not load data from ' . self::URI . '!');
|
||||
|
||||
$activities = $html->find('div#activite/li');
|
||||
|
||||
if(!$activities)
|
||||
returnServerError('Failed to find activities!');
|
||||
|
||||
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>';
|
||||
|
||||
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)){
|
||||
continue; // Skip this item
|
||||
}
|
||||
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
}
|
70
bridges/CollegeDeFranceBridge.php
Normal file
70
bridges/CollegeDeFranceBridge.php
Normal file
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
class CollegeDeFranceBridge extends BridgeAbstract{
|
||||
|
||||
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";
|
||||
|
||||
public function collectData(){
|
||||
$months = array(
|
||||
'01' => 'janv.',
|
||||
'02' => 'févr.',
|
||||
'03' => 'mars',
|
||||
'04' => 'avr.',
|
||||
'05' => 'mai',
|
||||
'06' => 'juin',
|
||||
'07' => 'juil.',
|
||||
'08' => 'août',
|
||||
'09' => 'sept.',
|
||||
'10' => 'oct.',
|
||||
'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="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')
|
||||
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"
|
||||
//
|
||||
// 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">
|
||||
$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
|
||||
$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',
|
||||
trim(str_replace(
|
||||
array_values($months),
|
||||
array_keys($months),
|
||||
$element->find('.date', 0)->plaintext
|
||||
)),
|
||||
$timezone
|
||||
);
|
||||
}
|
||||
$item['timestamp'] = $d->format('U');
|
||||
$item['content'] = $element->find('.lecturer', 0)->innertext . ' - ' . $element->find('.title', 0)->innertext;
|
||||
$item['uri'] = self::URI . $element->href;
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
}
|
26
bridges/CommonDreamsBridge.php
Normal file
26
bridges/CommonDreamsBridge.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
class CommonDreamsBridge extends FeedExpander {
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
protected function parseItem($newsItem){
|
||||
$item = parent::parseItem($newsItem);
|
||||
$item['content'] = $this->CommonDreamsExtractContent($item['uri']);
|
||||
return $item;
|
||||
}
|
||||
|
||||
private function CommonDreamsExtractContent($url) {
|
||||
$html3 = getSimpleHTMLDOMCached($url);
|
||||
$text = $html3->find('div[class=field--type-text-with-summary]', 0)->innertext;
|
||||
$html3->clear();
|
||||
unset ($html3);
|
||||
return $text;
|
||||
}
|
||||
}
|
39
bridges/CopieDoubleBridge.php
Normal file
39
bridges/CopieDoubleBridge.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
class CopieDoubleBridge extends BridgeAbstract{
|
||||
|
||||
const MAINTAINER = "superbaillot.net";
|
||||
const NAME = "CopieDouble";
|
||||
const URI = "http://www.copie-double.com/";
|
||||
const CACHE_TIMEOUT = 14400; // 4h
|
||||
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)
|
||||
{
|
||||
$td = $element->find('td', 0);
|
||||
if($td->class == "couleur_1")
|
||||
{
|
||||
$item = array();
|
||||
|
||||
$title = $td->innertext;
|
||||
$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);
|
||||
$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;
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
61
bridges/CourrierInternationalBridge.php
Normal file
61
bridges/CourrierInternationalBridge.php
Normal file
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
class CourrierInternationalBridge extends BridgeAbstract{
|
||||
|
||||
const MAINTAINER = "teromene";
|
||||
const NAME = "Courrier International Bridge";
|
||||
const URI = "http://CourrierInternational.com/";
|
||||
const CACHE_TIMEOUT = 300; // 5 min
|
||||
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");
|
||||
|
||||
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));
|
||||
|
||||
$dateTime = date_parse($page->find("time",0));
|
||||
|
||||
$item['timestamp'] = mktime(
|
||||
$dateTime['hour'],
|
||||
$dateTime['minute'],
|
||||
$dateTime['second'],
|
||||
$dateTime['month'],
|
||||
$dateTime['day'],
|
||||
$dateTime['year']
|
||||
);
|
||||
|
||||
$this->items[] = $item;
|
||||
$article_count ++;
|
||||
if($article_count > 5) break;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
53
bridges/CpasbienBridge.php
Normal file
53
bridges/CpasbienBridge.php
Normal file
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
class CpasbienBridge extends BridgeAbstract {
|
||||
|
||||
const MAINTAINER = "lagaisse";
|
||||
const NAME = "Cpasbien Bridge";
|
||||
const URI = "http://www.cpasbien.io";
|
||||
const CACHE_TIMEOUT = 86400; // 24h
|
||||
const DESCRIPTION = "Returns latest torrents from a request query";
|
||||
|
||||
const PARAMETERS = array( array(
|
||||
'q'=>array(
|
||||
'name'=>'Search',
|
||||
'required'=>true,
|
||||
'title'=>'Type your search'
|
||||
)
|
||||
));
|
||||
|
||||
public function collectData(){
|
||||
$request = str_replace(" ","-",trim($this->getInput('q')));
|
||||
$html = getSimpleHTMLDOM(self::URI.'/recherche/'.urlencode($request).'.html')
|
||||
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'));
|
||||
|
||||
$item = array();
|
||||
$item['author'] = $episode->find('a', 0)->text();
|
||||
$item['title'] = $episode->find('a', 0)->text();
|
||||
$textefiche=$htmlepisode->find('#textefiche', 0)->find('p',1);
|
||||
if (isset($textefiche)) {
|
||||
$item['content'] = $textefiche->text();
|
||||
} else {
|
||||
$p=$htmlepisode->find('#textefiche',0)->find('p');
|
||||
if(!empty($p)){
|
||||
$item['content'] = $htmlepisode->find('#textefiche', 0)->find('p',0)->text();
|
||||
}
|
||||
}
|
||||
|
||||
$item['id'] = $episode->find('a', 0)->getAttribute('href');
|
||||
$item['uri'] = self::URI . $htmlepisode->find('#telecharger',0)->getAttribute('href');
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function getName(){
|
||||
return $this->getInput('q').' : '.self::NAME;
|
||||
}
|
||||
}
|
39
bridges/CryptomeBridge.php
Normal file
39
bridges/CryptomeBridge.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
class CryptomeBridge extends BridgeAbstract{
|
||||
|
||||
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 PARAMETERS = array( array(
|
||||
'n'=>array(
|
||||
'name'=>'number of elements',
|
||||
'type'=>'number',
|
||||
'defaultValue'=>20,
|
||||
'exampleValue'=>10
|
||||
)
|
||||
));
|
||||
|
||||
public function collectData(){
|
||||
$html = getSimpleHTMLDOM(self::URI)
|
||||
or returnServerError('Could not request Cryptome.');
|
||||
$number=$this->getInput('n');
|
||||
if (!empty($number)) { /* number of documents */
|
||||
$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);
|
||||
$this->items[] = $item;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
114
bridges/DailymotionBridge.php
Normal file
114
bridges/DailymotionBridge.php
Normal file
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
class DailymotionBridge extends BridgeAbstract{
|
||||
|
||||
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 PARAMETERS = array (
|
||||
'By username' => array(
|
||||
'u'=>array(
|
||||
'name'=>'username',
|
||||
'required'=>true
|
||||
)
|
||||
),
|
||||
|
||||
'By playlist id' => array(
|
||||
'p'=>array(
|
||||
'name'=>'playlist id',
|
||||
'required'=>true
|
||||
)
|
||||
),
|
||||
|
||||
'From search results' => array(
|
||||
's'=>array(
|
||||
'name'=>'Search keyword',
|
||||
'required'=>true
|
||||
),
|
||||
'pa'=>array(
|
||||
'name'=>'Page',
|
||||
'type'=>'number'
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
function getMetadata($id) {
|
||||
$metadata=array();
|
||||
$html2 = getSimpleHTMLDOM(self::URI.'video/'.$id);
|
||||
if(!$html2){
|
||||
return $metadata;
|
||||
}
|
||||
|
||||
$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['thumbnailUri'] = $html2->find('meta[property=og:image]', 0)->getAttribute('content');
|
||||
$metadata['uri'] = $html2->find('meta[property=og:url]', 0)->getAttribute('content');
|
||||
return $metadata;
|
||||
}
|
||||
|
||||
public function collectData(){
|
||||
$html = '';
|
||||
$limit = 5;
|
||||
$count = 0;
|
||||
|
||||
$html = getSimpleHTMLDOM($this->getURI())
|
||||
or returnServerError('Could not request Dailymotion.');
|
||||
|
||||
foreach($html->find('div.media a.preview_link') as $element) {
|
||||
if($count < $limit) {
|
||||
$item = array();
|
||||
$item['id'] = str_replace('/video/', '', strtok($element->href, '_'));
|
||||
$metadata = $this->getMetadata($item['id']);
|
||||
if(empty($metadata)){
|
||||
continue;
|
||||
}
|
||||
$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>';
|
||||
$this->items[] = $item;
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
switch($this->queriedContext){
|
||||
case 'By username':
|
||||
$specific=$this->getInput('u');
|
||||
break;
|
||||
case 'By playlist id':
|
||||
$specific=strtok($this->getInput('p'), '_');
|
||||
break;
|
||||
case 'From search results':
|
||||
$specific=$this->getInput('s');
|
||||
break;
|
||||
}
|
||||
|
||||
return $specific.' : Dailymotion Bridge';
|
||||
}
|
||||
|
||||
public function getURI(){
|
||||
$uri=self::URI;
|
||||
switch($this->queriedContext){
|
||||
case 'By username':
|
||||
$uri.='user/'
|
||||
.urlencode($this->getInput('u')).'/1';
|
||||
break;
|
||||
case 'By playlist id':
|
||||
$uri.='playlist/'
|
||||
.urlencode(strtok($this->getInput('p'), '_'));
|
||||
break;
|
||||
case 'From search results':
|
||||
$uri.='search/'
|
||||
.urlencode($this->getInput('s'));
|
||||
if($this->getInput('pa')){
|
||||
$uri.='/'.$this->getInput('pa');
|
||||
}
|
||||
break;
|
||||
}
|
||||
return $uri;
|
||||
}
|
||||
}
|
51
bridges/DanbooruBridge.php
Normal file
51
bridges/DanbooruBridge.php
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
class DanbooruBridge extends BridgeAbstract{
|
||||
|
||||
const MAINTAINER = "mitsukarenai";
|
||||
const NAME = "Danbooru";
|
||||
const URI = "http://donmai.us/";
|
||||
const CACHE_TIMEOUT = 1800; // 30min
|
||||
const DESCRIPTION = "Returns images from given page";
|
||||
|
||||
const PARAMETERS = array(
|
||||
'global'=>array(
|
||||
'p'=>array(
|
||||
'name'=>'page',
|
||||
'defaultValue'=>1,
|
||||
'type'=>'number'
|
||||
),
|
||||
't'=>array('name'=>'tags')
|
||||
),
|
||||
0=>array()
|
||||
);
|
||||
|
||||
const PATHTODATA='article';
|
||||
const IDATTRIBUTE='data-id';
|
||||
|
||||
protected function getFullURI(){
|
||||
return $this->getURI().'posts?'
|
||||
.'&page='.$this->getInput('p')
|
||||
.'&tags='.urlencode($this->getInput('t'));
|
||||
}
|
||||
|
||||
protected function getItemFromElement($element){
|
||||
$item = array();
|
||||
$item['uri'] = $this->getURI().$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');
|
||||
$item['title'] = $this->getName().' | '.$item['postid'];
|
||||
$item['content'] = '<a href="' . $item['uri'] . '"><img src="' . $thumbnailUri . '" /></a><br>Tags: '.$item['tags'];
|
||||
return $item;
|
||||
}
|
||||
|
||||
public function collectData(){
|
||||
$html = getSimpleHTMLDOM($this->getFullURI())
|
||||
or returnServerError('Could not request '.$this->getName());
|
||||
|
||||
foreach($html->find(static::PATHTODATA) as $element) {
|
||||
$this->items[] = $this->getItemFromElement($element);
|
||||
}
|
||||
}
|
||||
}
|
23
bridges/DansTonChatBridge.php
Normal file
23
bridges/DansTonChatBridge.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
class DansTonChatBridge extends BridgeAbstract{
|
||||
|
||||
const MAINTAINER = "Astalaseven";
|
||||
const NAME = "DansTonChat Bridge";
|
||||
const URI = "http://danstonchat.com/";
|
||||
const CACHE_TIMEOUT = 21600; //6h
|
||||
const DESCRIPTION = "Returns latest quotes from DansTonChat.";
|
||||
|
||||
public function collectData(){
|
||||
|
||||
$html = getSimpleHTMLDOM(self::URI.'latest.html')
|
||||
or returnServerError('Could not request DansTonChat.');
|
||||
|
||||
foreach($html->find('div.item') as $element) {
|
||||
$item = array();
|
||||
$item['uri'] = $element->find('a', 0)->href;
|
||||
$item['title'] = 'DansTonChat '.$element->find('a', 1)->plaintext;
|
||||
$item['content'] = $element->find('a', 0)->innertext;
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
}
|
57
bridges/DauphineLibereBridge.php
Normal file
57
bridges/DauphineLibereBridge.php
Normal file
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
class DauphineLibereBridge extends FeedExpander {
|
||||
|
||||
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 PARAMETERS = array( array(
|
||||
'u'=>array(
|
||||
'name'=>'Catégorie de l\'article',
|
||||
'type'=>'list',
|
||||
'values'=>array(
|
||||
'À la une'=>'',
|
||||
'France Monde'=>'france-monde',
|
||||
'Faits Divers'=>'faits-divers',
|
||||
'Économie et Finance'=>'economie-et-finance',
|
||||
'Politique'=>'politique',
|
||||
'Sport'=>'sport',
|
||||
'Ain'=>'ain',
|
||||
'Alpes-de-Haute-Provence'=>'haute-provence',
|
||||
'Hautes-Alpes'=>'hautes-alpes',
|
||||
'Ardèche'=>'ardeche',
|
||||
'Drôme'=>'drome',
|
||||
'Isère Sud'=>'isere-sud',
|
||||
'Savoie'=>'savoie',
|
||||
'Haute-Savoie'=>'haute-savoie',
|
||||
'Vaucluse'=>'vaucluse'
|
||||
)
|
||||
)
|
||||
));
|
||||
|
||||
public function collectData(){
|
||||
$url = self::URI . 'rss';
|
||||
|
||||
if (empty($this->getInput('u'))) {
|
||||
$url = self::URI . $this->getInput('u') . '/rss';
|
||||
}
|
||||
|
||||
$this->collectExpandableDatas($url, 10);
|
||||
}
|
||||
|
||||
protected function parseItem($newsItem){
|
||||
$item = parent::parseItem($newsItem);
|
||||
$item['content'] = $this->ExtractContent($item['uri']);
|
||||
return $item;
|
||||
}
|
||||
|
||||
private function ExtractContent($url) {
|
||||
$html2 = getSimpleHTMLDOMCached($url);
|
||||
$text = $html2->find('div.column', 0)->innertext;
|
||||
$text = preg_replace('@<script[^>]*?>.*?</script>@si', '', $text);
|
||||
return $text;
|
||||
}
|
||||
}
|
||||
?>
|
49
bridges/DemoBridge.php
Normal file
49
bridges/DemoBridge.php
Normal file
@@ -0,0 +1,49 @@
|
||||
<?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 PARAMETERS = array(
|
||||
'testCheckbox' => array(
|
||||
'testCheckbox'=>array(
|
||||
'type'=>'checkbox',
|
||||
'name'=>'test des checkbox'
|
||||
)
|
||||
),
|
||||
|
||||
'testList' => array(
|
||||
'testList'=>array(
|
||||
'type'=>'list',
|
||||
'name'=>'test des listes',
|
||||
'values'=>array(
|
||||
'Test'=>'test',
|
||||
'Test 2'=>'test2'
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
'testNumber' => array(
|
||||
'testNumber'=>array(
|
||||
'type'=>'number',
|
||||
'name'=>'test des numéros',
|
||||
'exampleValue'=>'1515632'
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
public function collectData(){
|
||||
|
||||
$item = array();
|
||||
$item['author'] = "Me!";
|
||||
$item['title'] = "Test";
|
||||
$item['content'] = "Awesome content !";
|
||||
$item['id'] = "Lalala";
|
||||
$item['uri'] = "http://example.com/test";
|
||||
|
||||
$this->items[] = $item;
|
||||
|
||||
}
|
||||
}
|
51
bridges/DeveloppezDotComBridge.php
Normal file
51
bridges/DeveloppezDotComBridge.php
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
class DeveloppezDotComBridge extends FeedExpander {
|
||||
|
||||
const MAINTAINER = "polopollo";
|
||||
const NAME = "Developpez.com Actus (FR)";
|
||||
const URI = "http://www.developpez.com/";
|
||||
const CACHE_TIMEOUT = 1800; // 30min
|
||||
const DESCRIPTION = "Returns the 15 newest posts from DeveloppezDotCom (full text).";
|
||||
|
||||
public function collectData(){
|
||||
$this->collectExpandableDatas(self::URI . 'index/rss', 15);
|
||||
}
|
||||
|
||||
protected function parseItem($newsItem){
|
||||
$item = parent::parseItem($newsItem);
|
||||
$item['content'] = $this->DeveloppezDotComExtractContent($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)
|
||||
{
|
||||
$search = array(chr(145),
|
||||
chr(146),
|
||||
chr(147),
|
||||
chr(148),
|
||||
chr(151));
|
||||
|
||||
$replace = array("'",
|
||||
"'",
|
||||
'"',
|
||||
'"',
|
||||
'-');
|
||||
|
||||
return str_replace($search, $replace, $string);
|
||||
}
|
||||
|
||||
private function DeveloppezDotComExtractContent($url) {
|
||||
$articleHTMLContent = getSimpleHTMLDOMCached($url);
|
||||
$text = $this->convert_smart_quotes($articleHTMLContent->find('div.content', 0)->innertext);
|
||||
$text = utf8_encode($text);
|
||||
return trim($text);
|
||||
}
|
||||
}
|
36
bridges/DilbertBridge.php
Normal file
36
bridges/DilbertBridge.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
class DilbertBridge extends BridgeAbstract {
|
||||
|
||||
const MAINTAINER = 'kranack';
|
||||
const NAME = 'Dilbert Daily Strip';
|
||||
const URI = 'http://dilbert.com';
|
||||
const CACHE_TIMEOUT = 21600; // 6h
|
||||
const DESCRIPTION = 'The Unofficial Dilbert Daily Comic Strip';
|
||||
|
||||
public function collectData(){
|
||||
|
||||
$html = getSimpleHTMLDOM($this->getURI()) or returnServerError('Could not request Dilbert: '.$this->getURI());
|
||||
|
||||
foreach ($html->find('section.comic-item') as $element) {
|
||||
|
||||
$img = $element->find('img', 0);
|
||||
$link = $element->find('a', 0);
|
||||
$comic = $img->src;
|
||||
$title = $link->alt;
|
||||
$url = $link->href;
|
||||
$date = substr($url, 25);
|
||||
if (empty($title))
|
||||
$title = 'Dilbert Comic Strip on '.$date;
|
||||
$date = strtotime($date);
|
||||
|
||||
$item = array();
|
||||
$item['uri'] = $url;
|
||||
$item['title'] = $title;
|
||||
$item['author'] = 'Scott Adams';
|
||||
$item['timestamp'] = $date;
|
||||
$item['content'] = '<img src="'.$comic.'" alt="'.$img->alt.'" />';
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
11
bridges/DollbooruBridge.php
Normal file
11
bridges/DollbooruBridge.php
Normal file
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
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";
|
||||
|
||||
}
|
41
bridges/DuckDuckGoBridge.php
Normal file
41
bridges/DuckDuckGoBridge.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
class DuckDuckGoBridge extends BridgeAbstract{
|
||||
|
||||
const MAINTAINER = "Astalaseven";
|
||||
const NAME = "DuckDuckGo";
|
||||
const URI = "https://duckduckgo.com/";
|
||||
const CACHE_TIMEOUT = 21600; // 6h
|
||||
const DESCRIPTION = "Returns results from DuckDuckGo.";
|
||||
|
||||
const SORT_DATE = '+sort:date';
|
||||
const SORT_RELEVANCE = '';
|
||||
|
||||
const PARAMETERS = array( array(
|
||||
'u'=>array(
|
||||
'name'=>'keyword',
|
||||
'required'=>true),
|
||||
'sort'=>array(
|
||||
'name'=>'sort by',
|
||||
'type'=>'list',
|
||||
'required'=>false,
|
||||
'values'=>array(
|
||||
'date'=>self::SORT_DATE,
|
||||
'relevance'=>self::SORT_RELEVANCE
|
||||
),
|
||||
'defaultValue'=>self::SORT_DATE
|
||||
)
|
||||
));
|
||||
|
||||
public function collectData(){
|
||||
$html = getSimpleHTMLDOM(self::URI.'html/?q='.$this->getInput('u').$this->getInput('sort'))
|
||||
or returnServerError('Could not request DuckDuckGo.');
|
||||
|
||||
foreach($html->find('div.results_links') as $element) {
|
||||
$item = array();
|
||||
$item['uri'] = $element->find('a', 0)->href;
|
||||
$item['title'] = $element->find('a', 1)->innertext;
|
||||
$item['content'] = $element->find('div.snippet', 0)->plaintext;
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
}
|
66
bridges/EZTVBridge.php
Normal file
66
bridges/EZTVBridge.php
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
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 PARAMETERS = array( array(
|
||||
'i'=>array(
|
||||
'name'=>'Show ids',
|
||||
'exampleValue'=>'showID1,showID2,…',
|
||||
'required'=>true
|
||||
)
|
||||
));
|
||||
|
||||
public function collectData(){
|
||||
|
||||
// Make timestamp from relative released time in table
|
||||
function makeTimestamp($relativeReleaseTime){
|
||||
|
||||
$relativeDays = 0;
|
||||
$relativeHours = 0;
|
||||
|
||||
foreach (explode(" ",$relativeReleaseTime) as $relativeTimeElement) {
|
||||
if (substr($relativeTimeElement,-1) == "d") $relativeDays = substr($relativeTimeElement,0,-1);
|
||||
if (substr($relativeTimeElement,-1) == "h") $relativeHours = substr($relativeTimeElement,0,-1);
|
||||
}
|
||||
return mktime(date('h')-$relativeHours,0,0,date('m'),date('d')-$relativeDays,date('Y'));
|
||||
}
|
||||
|
||||
// Loop on show ids
|
||||
$showList = explode(",",$this->getInput('i'));
|
||||
foreach($showList as $showID){
|
||||
|
||||
// Get show page
|
||||
$html = getSimpleHTMLDOM(self::URI.'shows/'.rawurlencode($showID).'/')
|
||||
or returnServerError('Could not request EZTV for id "'.$showID.'"');
|
||||
|
||||
// Loop on each element that look like an episode entry...
|
||||
foreach($html->find('.forum_header_border') as $element) {
|
||||
|
||||
// Filter entries that are not episode entries
|
||||
$ep = $element->find('td',1);
|
||||
if (empty($ep)) continue;
|
||||
$epinfo = $ep->find('.epinfo',0);
|
||||
$released = $element->find('td',3);
|
||||
if (empty($epinfo)) continue;
|
||||
if (empty($released->plaintext)) continue;
|
||||
|
||||
// Filter entries that are older than 1 week
|
||||
if ($released->plaintext == '>1 week') continue;
|
||||
|
||||
// Fill item
|
||||
$item = array();
|
||||
$item['uri'] = self::URI.$epinfo->href;
|
||||
$item['id'] = $item['uri'];
|
||||
$item['timestamp'] = makeTimestamp($released->plaintext);
|
||||
$item['title'] = $epinfo->plaintext;
|
||||
$item['content'] = $epinfo->alt;
|
||||
if(isset($item['title']))
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
35
bridges/EliteDangerousGalnetBridge.php
Normal file
35
bridges/EliteDangerousGalnetBridge.php
Normal file
@@ -0,0 +1,35 @@
|
||||
<?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";
|
||||
|
||||
public function collectData()
|
||||
{
|
||||
$html = getSimpleHTMLDOM(self::URI)
|
||||
or returnServerError('Error while downloading the website content');
|
||||
foreach($html->find('div.article') as $element) {
|
||||
$item = array();
|
||||
|
||||
$uri = $element->find('h3 a', 0)->href;
|
||||
$uri = self::URI . substr($uri,strlen('/galnet/'));
|
||||
$item['uri'] = $uri;
|
||||
|
||||
$title = $element->find('h3 a', 0)->plaintext;
|
||||
$item['title'] = substr($title, 1); //remove the space between icon and title
|
||||
|
||||
$content = $element->find('p', -1)->innertext;
|
||||
$item['content'] = $content;
|
||||
|
||||
$date = $element->find('p.small', 0)->innertext;
|
||||
$article_year = substr($date, -4) - 1286; //Convert E:D date to actual date
|
||||
$date = substr($date, 0, -4) . $article_year;
|
||||
$item['timestamp'] = strtotime($date);
|
||||
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
}
|
74
bridges/ElsevierBridge.php
Normal file
74
bridges/ElsevierBridge.php
Normal file
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
class ElsevierBridge extends BridgeAbstract{
|
||||
const MAINTAINER = 'Pierre Mazière';
|
||||
const NAME = 'Elsevier journals recent articles';
|
||||
const URI = 'http://www.journals.elsevier.com/';
|
||||
const CACHE_TIMEOUT = 43200; //12h
|
||||
const DESCRIPTION = 'Returns the recent articles published in Elsevier journals';
|
||||
|
||||
const PARAMETERS = array( array(
|
||||
'j'=>array(
|
||||
'name'=>'Journal name',
|
||||
'required'=>true,
|
||||
'exampleValue'=>'academic-pediactrics',
|
||||
'title'=>'Insert html-part of your journal'
|
||||
)
|
||||
));
|
||||
|
||||
// Extracts the list of names from an article as string
|
||||
private function ExtractArticleName ($article){
|
||||
$names = $article->find('small', 0);
|
||||
if($names)
|
||||
return trim($names->plaintext);
|
||||
return '';
|
||||
}
|
||||
|
||||
// Extracts the timestamp from an article
|
||||
private function ExtractArticleTimestamp ($article){
|
||||
$time = $article->find('.article-info', 0);
|
||||
if($time){
|
||||
$timestring = trim($time->plaintext);
|
||||
/*
|
||||
The format depends on the age of an article:
|
||||
- Available online 29 July 2016
|
||||
- July 2016
|
||||
- May–June 2016
|
||||
*/
|
||||
if(preg_match('/\S*(\d+\s\S+\s\d{4})/ims', $timestring, $matches)){
|
||||
return strtotime($matches[0]);
|
||||
} elseif (preg_match('/[A-Za-z]+\-([A-Za-z]+\s\d{4})/ims', $timestring, $matches)){
|
||||
return strtotime($matches[0]);
|
||||
} elseif (preg_match('/([A-Za-z]+\s\d{4})/ims', $timestring, $matches)){
|
||||
return strtotime($matches[0]);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Extracts the content from an article
|
||||
private function ExtractArticleContent ($article){
|
||||
$content = $article->find('.article-content', 0);
|
||||
if($content){
|
||||
return trim($content->plaintext);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
public function collectData(){
|
||||
$uri = self::URI . $this->getInput('j') . '/recent-articles/';
|
||||
$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);
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
30
bridges/EstCeQuonMetEnProdBridge.php
Normal file
30
bridges/EstCeQuonMetEnProdBridge.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
class EstCeQuonMetEnProdBridge extends BridgeAbstract {
|
||||
|
||||
const MAINTAINER = 'ORelio';
|
||||
const NAME = 'Est-ce qu\'on met en prod aujourd\'hui ?';
|
||||
const URI = 'https://www.estcequonmetenprodaujourdhui.info/';
|
||||
const CACHE_TIMEOUT = 21600; // 6h
|
||||
const DESCRIPTION = 'Should we put a website in production today? (French)';
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
$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 />')));
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
?>
|
210
bridges/FacebookBridge.php
Normal file
210
bridges/FacebookBridge.php
Normal file
@@ -0,0 +1,210 @@
|
||||
<?php
|
||||
class FacebookBridge extends BridgeAbstract{
|
||||
|
||||
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 PARAMETERS =array( array(
|
||||
'u'=>array(
|
||||
'name'=>'Username',
|
||||
'required'=>true
|
||||
)
|
||||
));
|
||||
|
||||
private $authorName='';
|
||||
|
||||
public function collectData(){
|
||||
|
||||
//Extract a string using start and end delimiters
|
||||
function ExtractFromDelimiters($string, $start, $end) {
|
||||
if (strpos($string, $start) !== false) {
|
||||
$section_retrieved = substr($string, strpos($string, $start) + strlen($start));
|
||||
$section_retrieved = substr($section_retrieved, 0, strpos($section_retrieved, $end));
|
||||
return $section_retrieved;
|
||||
} return false;
|
||||
}
|
||||
|
||||
//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];
|
||||
};
|
||||
|
||||
$html = null;
|
||||
|
||||
//Handle captcha response sent by the viewer
|
||||
if (isset($_POST['captcha_response']))
|
||||
{
|
||||
if (session_status() == PHP_SESSION_NONE)
|
||||
session_start();
|
||||
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),
|
||||
),
|
||||
);
|
||||
$context = stream_context_create($http_options);
|
||||
$html = getContents($captcha_action, false, $context);
|
||||
if ($html === FALSE) { returnServerError('Failed to submit captcha response back to Facebook'); }
|
||||
unset($_SESSION['captcha_fields']);
|
||||
$html = str_get_html($html);
|
||||
}
|
||||
unset($_SESSION['captcha_fields']);
|
||||
unset($_SESSION['captcha_action']);
|
||||
}
|
||||
|
||||
//Retrieve page contents
|
||||
if (is_null($html)) {
|
||||
if (!strpos($this->getInput('u'), "/")) {
|
||||
$html = getSimpleHTMLDOM(self::URI.urlencode($this->getInput('u')).'?_fb_noscript=1')
|
||||
or returnServerError('No results for this query.');
|
||||
} else {
|
||||
$html = getSimpleHTMLDOM(self::URI.'pages/'.$this->getInput('u').'?_fb_noscript=1')
|
||||
or returnServerError('No results for this query.');
|
||||
}
|
||||
}
|
||||
|
||||
//Handle captcha form?
|
||||
$captcha = $html->find('div.captcha_interstitial', 0);
|
||||
if (!is_null($captcha))
|
||||
{
|
||||
//Save form for submitting after getting captcha response
|
||||
if (session_status() == PHP_SESSION_NONE)
|
||||
session_start();
|
||||
$captcha_fields = array();
|
||||
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;
|
||||
|
||||
//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));
|
||||
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>');
|
||||
}
|
||||
|
||||
//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);
|
||||
|
||||
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';
|
||||
$this->authorName = $author;
|
||||
|
||||
foreach($element->children() as $post) {
|
||||
|
||||
$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);
|
||||
|
||||
//Remove html nodes, keep only img, links, basic formatting
|
||||
$content = strip_tags($content,'<a><img><i><u>');
|
||||
|
||||
//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);
|
||||
|
||||
//Retrieve date of the post
|
||||
$date = $post->find("abbr")[0];
|
||||
if(isset($date) && $date->hasAttribute('data-utime')) {
|
||||
$date = $date->getAttribute('data-utime');
|
||||
} else {
|
||||
$date = 0;
|
||||
}
|
||||
|
||||
//Build title from username and 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")).'...';
|
||||
|
||||
//Build and add final item
|
||||
$item['uri'] = self::URI.$post->find('abbr')[0]->parent()->getAttribute('href');
|
||||
$item['content'] = $content;
|
||||
$item['title'] = $title;
|
||||
$item['author'] = $author;
|
||||
$item['timestamp'] = $date;
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getName() {
|
||||
return (isset($this->authorName) ? $this->authorName.' - ' : '').'Facebook Bridge';
|
||||
}
|
||||
}
|
62
bridges/FeedExpanderExampleBridge.php
Normal file
62
bridges/FeedExpanderExampleBridge.php
Normal file
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
class FeedExpanderExampleBridge extends FeedExpander {
|
||||
|
||||
const MAINTAINER = 'logmanoriginal';
|
||||
const NAME = 'FeedExpander Example';
|
||||
const URI = '#';
|
||||
const DESCRIPTION = 'Example bridge to test FeedExpander';
|
||||
|
||||
const PARAMETERS = array(
|
||||
'Feed' => array(
|
||||
'version' => array(
|
||||
'name' => 'Version',
|
||||
'type' => 'list',
|
||||
'required' => true,
|
||||
'title' => 'Select your feed format/version',
|
||||
'defaultValue' => 'RSS 2.0',
|
||||
'values' => array(
|
||||
'RSS 0.91' => 'rss_0_9_1',
|
||||
'RSS 1.0' => 'rss_1_0',
|
||||
'RSS 2.0' => 'rss_2_0',
|
||||
'ATOM 1.0' => 'atom_1_0'
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
public function collectData(){
|
||||
switch($this->getInput('version')){
|
||||
case 'rss_0_9_1':
|
||||
parent::collectExpandableDatas('http://static.userland.com/gems/backend/sampleRss.xml');
|
||||
break;
|
||||
case 'rss_1_0':
|
||||
parent::collectExpandableDatas('http://feeds.nature.com/nature/rss/current?format=xml');
|
||||
break;
|
||||
case 'rss_2_0':
|
||||
parent::collectExpandableDatas('http://feeds.rssboard.org/rssboard?format=xml');
|
||||
break;
|
||||
case 'atom_1_0':
|
||||
parent::collectExpandableDatas('http://segfault.linuxmint.com/feed/atom/');
|
||||
break;
|
||||
default: returnClientError('Unknown version ' . $this->getInput('version') . '!');
|
||||
}
|
||||
}
|
||||
|
||||
protected function parseItem($newsItem) {
|
||||
switch($this->getInput('version')){
|
||||
case 'rss_0_9_1':
|
||||
return $this->parseRSS_0_9_1_Item($newsItem);
|
||||
break;
|
||||
case 'rss_1_0':
|
||||
return $this->parseRSS_1_0_Item($newsItem);
|
||||
break;
|
||||
case 'rss_2_0':
|
||||
return $this->parseRSS_2_0_Item($newsItem);
|
||||
break;
|
||||
case 'atom_1_0':
|
||||
return $this->parseATOMItem($newsItem);
|
||||
break;
|
||||
default: returnClientError('Unknown version ' . $this->getInput('version') . '!');
|
||||
}
|
||||
}
|
||||
}
|
23
bridges/FierPandaBridge.php
Normal file
23
bridges/FierPandaBridge.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
class FierPandaBridge extends BridgeAbstract {
|
||||
|
||||
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.";
|
||||
|
||||
public function collectData(){
|
||||
$html = getSimpleHTMLDOM(self::URI) or returnServerError('Could not request Fier Panda.');
|
||||
|
||||
foreach($html->find('div.container-content article') as $element) {
|
||||
$item = array();
|
||||
$item['uri'] = $this->getURI().$element->find('a', 0)->href;
|
||||
$item['title'] = trim($element->find('h1 a', 0)->innertext);
|
||||
// Remove the link at the end of the article
|
||||
$element->find('p a', 0)->outertext = '';
|
||||
$item['content'] = $element->find('p', 0)->innertext;
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,35 +1,42 @@
|
||||
<?php
|
||||
/**
|
||||
* RssBridgeFlickrExplore
|
||||
* Returns the newest interesting images from http://www.flickr.com/explore
|
||||
*
|
||||
* @name Flickr Explore
|
||||
* @description Returns the latest interesting images from Flickr
|
||||
*/
|
||||
class FlickrExploreBridge extends BridgeAbstract{
|
||||
|
||||
public function collectData(array $param){
|
||||
$html = file_get_html('http://www.flickr.com/explore') or $this->returnError('Could not request Flickr.', 404);
|
||||
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";
|
||||
|
||||
foreach($html->find('span.photo_container') as $element) {
|
||||
$item = new \Item();
|
||||
$item->uri = 'http://flickr.com'.$element->find('a',0)->href;
|
||||
$item->thumbnailUri = $element->find('img',0)->getAttribute('data-defer-src');
|
||||
$item->content = '<a href="' . $item->uri . '"><img src="' . $item->thumbnailUri . '" /></a>'; // FIXME: Filter javascript ?
|
||||
$item->title = $element->find('a',0)->title;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return 'Flickr Explore';
|
||||
}
|
||||
|
||||
public function getURI(){
|
||||
return 'http://www.flickr.com/explore';
|
||||
}
|
||||
|
||||
public function getCacheDuration(){
|
||||
return 21600; // 6 hours
|
||||
}
|
||||
}
|
48
bridges/FlickrTagBridge.php
Normal file
48
bridges/FlickrTagBridge.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
40
bridges/FootitoBridge.php
Normal file
40
bridges/FootitoBridge.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
class FootitoBridge extends BridgeAbstract{
|
||||
|
||||
const MAINTAINER = "superbaillot.net";
|
||||
const NAME = "Footito";
|
||||
const URI = "http://www.footito.fr/";
|
||||
const DESCRIPTION = "Footito";
|
||||
|
||||
public function collectData(){
|
||||
$html = getSimpleHTMLDOM(self::URI)
|
||||
or returnServerError('Could not request Footito.');
|
||||
|
||||
foreach($html->find('div.post') as $element) {
|
||||
$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 );
|
||||
|
||||
$item['content'] = $content;
|
||||
|
||||
$title = $element->find('.contenu .texte ', 0)->plaintext;
|
||||
$item['title'] = $title;
|
||||
|
||||
$info = $element->find('div.infos', 0);
|
||||
|
||||
$item['timestamp'] = strtotime($info->find('time', 0)->datetime);
|
||||
$item['author'] = $info->find('a.auteur', 0)->plaintext;
|
||||
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
}
|
68
bridges/FourchanBridge.php
Normal file
68
bridges/FourchanBridge.php
Normal file
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
class FourchanBridge extends BridgeAbstract{
|
||||
|
||||
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 PARAMETERS = array( array(
|
||||
'c'=>array(
|
||||
'name'=>'Thread category',
|
||||
'required'=>true
|
||||
),
|
||||
't'=>array(
|
||||
'name'=>'Thread number',
|
||||
'type'=>'number',
|
||||
'required'=>true
|
||||
)
|
||||
));
|
||||
|
||||
public function getURI(){
|
||||
return static::URI.$this->getInput('c').'/thread/'.$this->getInput('t');
|
||||
|
||||
}
|
||||
|
||||
public function collectData(){
|
||||
|
||||
$html = getSimpleHTMLDOM($this->getURI())
|
||||
or returnServerError("Could not request 4chan, thread not found");
|
||||
|
||||
foreach($html->find('div.postContainer') as $element) {
|
||||
$item = array();
|
||||
$item['id'] = $element->find('.post', 0)->getAttribute('id');
|
||||
$item['uri'] = $this->getURI().'#'.$item['id'];
|
||||
$item['timestamp'] = $element->find('span.dateTime', 0)->getAttribute('data-utc');
|
||||
$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)
|
||||
$item['imageThumb'] = 'http://i.imgur.com/eO0cxf9.jpg';
|
||||
}
|
||||
if(!empty($element->find('span.subject', 0)->innertext )) {
|
||||
$item['subject'] = $element->find('span.subject', 0)->innertext;
|
||||
}
|
||||
|
||||
$item['title'] = 'reply '.$item['id'].' | '.$item['author'];
|
||||
if(isset($item['subject'])){
|
||||
$item['title'] = $item['subject'].' - '.$item['title'];
|
||||
}
|
||||
|
||||
$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'];
|
||||
}
|
||||
$this->items[] = $item;
|
||||
}
|
||||
$this->items = array_reverse($this->items);
|
||||
}
|
||||
}
|
166
bridges/FuturaSciencesBridge.php
Normal file
166
bridges/FuturaSciencesBridge.php
Normal file
@@ -0,0 +1,166 @@
|
||||
<?php
|
||||
class FuturaSciencesBridge extends FeedExpander {
|
||||
|
||||
const MAINTAINER = 'ORelio';
|
||||
const NAME = 'Futura-Sciences Bridge';
|
||||
const URI = 'http://www.futura-sciences.com/';
|
||||
const DESCRIPTION = 'Returns the newest articles.';
|
||||
|
||||
const PARAMETERS = array( array(
|
||||
'feed'=> array(
|
||||
'name'=>'Feed',
|
||||
'type'=>'list',
|
||||
'values'=>array(
|
||||
'Les flux multi-magazines'=>array(
|
||||
'Les dernières actualités de Futura-Sciences'=>'actualites',
|
||||
'Les dernières définitions de Futura-Sciences'=>'definitions',
|
||||
'Les dernières photos de Futura-Sciences'=>'photos',
|
||||
'Les dernières questions - réponses de Futura-Sciences'=>'questions-reponses',
|
||||
'Les derniers dossiers de Futura-Sciences'=>'dossiers'
|
||||
),
|
||||
'Les flux Services'=> array(
|
||||
'Les cartes virtuelles de Futura-Sciences'=>'services/cartes-virtuelles',
|
||||
'Les fonds d\'écran de Futura-Sciences'=>'services/fonds-ecran'
|
||||
),
|
||||
'Les flux Santé'=>array(
|
||||
'Les dernières actualités de Futura-Santé'=>'sante/actualites',
|
||||
'Les dernières définitions de Futura-Santé'=>'sante/definitions',
|
||||
'Les dernières questions-réponses de Futura-Santé'=>'sante/question-reponses',
|
||||
'Les derniers dossiers de Futura-Santé'=>'sante/dossiers'
|
||||
),
|
||||
'Les flux High-Tech'=>array(
|
||||
'Les dernières actualités de Futura-High-Tech'=>'high-tech/actualites',
|
||||
'Les dernières astuces de Futura-High-Tech'=>'high-tech/question-reponses',
|
||||
'Les dernières définitions de Futura-High-Tech'=>'high-tech/definitions',
|
||||
'Les derniers dossiers de Futura-High-Tech'=>'high-tech/dossiers'
|
||||
),
|
||||
'Les flux Espace'=>array(
|
||||
'Les dernières actualités de Futura-Espace'=>'espace/actualites',
|
||||
'Les dernières définitions de Futura-Espace'=>'espace/definitions',
|
||||
'Les dernières questions-réponses de Futura-Espace'=>'espace/question-reponses',
|
||||
'Les derniers dossiers de Futura-Espace'=>'espace/dossiers'
|
||||
),
|
||||
'Les flux Environnement'=>array(
|
||||
'Les dernières actualités de Futura-Environnement'=>'environnement/actualites',
|
||||
'Les dernières définitions de Futura-Environnement'=>'environnement/definitions',
|
||||
'Les dernières questions-réponses de Futura-Environnement'=>'environnement/question-reponses',
|
||||
'Les derniers dossiers de Futura-Environnement'=>'environnement/dossiers'
|
||||
),
|
||||
'Les flux Maison'=>array(
|
||||
'Les dernières actualités de Futura-Maison'=>'maison/actualites',
|
||||
'Les dernières astuces de Futura-Maison'=>'maison/question-reponses',
|
||||
'Les dernières définitions de Futura-Maison'=>'maison/definitions',
|
||||
'Les derniers dossiers de Futura-Maison'=>'maison/dossiers'
|
||||
),
|
||||
'Les flux Nature'=>array(
|
||||
'Les dernières actualités de Futura-Nature'=>'nature/actualites',
|
||||
'Les dernières définitions de Futura-Nature'=>'nature/definitions',
|
||||
'Les dernières questions-réponses de Futura-Nature'=>'nature/question-reponses',
|
||||
'Les derniers dossiers de Futura-Nature'=>'nature/dossiers'
|
||||
),
|
||||
'Les flux Terre'=>array(
|
||||
'Les dernières actualités de Futura-Terre'=>'terre/actualites',
|
||||
'Les dernières définitions de Futura-Terre'=>'terre/definitions',
|
||||
'Les dernières questions-réponses de Futura-Terre'=>'terre/question-reponses',
|
||||
'Les derniers dossiers de Futura-Terre'=>'terre/dossiers'
|
||||
),
|
||||
'Les flux Matière'=>array(
|
||||
'Les dernières actualités de Futura-Matière'=>'matiere/actualites',
|
||||
'Les dernières définitions de Futura-Matière'=>'matiere/definitions',
|
||||
'Les dernières questions-réponses de Futura-Matière'=>'matiere/question-reponses',
|
||||
'Les derniers dossiers de Futura-Matière'=>'matiere/dossiers'
|
||||
),
|
||||
'Les flux Mathématiques'=>array(
|
||||
'Les dernières actualités de Futura-Mathématiques'=>'mathematiques/actualites',
|
||||
'Les derniers dossiers de Futura-Mathématiques'=>'mathematiques/dossiers'
|
||||
)
|
||||
)
|
||||
)
|
||||
));
|
||||
|
||||
public function collectData(){
|
||||
$url = self::URI . 'rss/' . $this->getInput('feed') . '.xml';
|
||||
$this->collectExpandableDatas($url, 10);
|
||||
}
|
||||
|
||||
protected function parseItem($newsItem){
|
||||
$item = parent::parseItem($newsItem);
|
||||
$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);
|
||||
return $item;
|
||||
}
|
||||
|
||||
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 StripRecursiveHTMLSection($string, $tag_name, $tag_start) {
|
||||
$open_tag = '<'.$tag_name;
|
||||
$close_tag = '</'.$tag_name.'>';
|
||||
$close_tag_length = strlen($close_tag);
|
||||
if (strpos($tag_start, $open_tag) === 0) {
|
||||
while (strpos($string, $tag_start) !== false) {
|
||||
$max_recursion = 100;
|
||||
$section_to_remove = null;
|
||||
$section_start = strpos($string, $tag_start);
|
||||
$search_offset = $section_start;
|
||||
do {
|
||||
$max_recursion--;
|
||||
$section_end = strpos($string, $close_tag, $search_offset);
|
||||
$search_offset = $section_end + $close_tag_length;
|
||||
$section_to_remove = substr($string, $section_start, $section_end - $section_start + $close_tag_length);
|
||||
$open_tag_count = substr_count($section_to_remove, $open_tag);
|
||||
$close_tag_count = substr_count($section_to_remove, $close_tag);
|
||||
} while ($open_tag_count > $close_tag_count && $max_recursion > 0);
|
||||
$string = str_replace($section_to_remove, '', $string);
|
||||
}
|
||||
}
|
||||
return $string;
|
||||
}
|
||||
|
||||
function ExtractArticleContent($article){
|
||||
$contents = $article->find('div.content', 0)->innertext;
|
||||
|
||||
foreach (array(
|
||||
'<div class="clear',
|
||||
'<div class="sharebar2',
|
||||
'<div class="diaporamafullscreen"',
|
||||
'<div style="margin-bottom:10px;" class="noprint"',
|
||||
'<div class="ficheprevnext',
|
||||
'<div class="bar noprint',
|
||||
'<div class="toolbar noprint',
|
||||
'<div class="addthis_toolbox',
|
||||
'<div class="noprint',
|
||||
'<div class="bg bglight border border-full noprint',
|
||||
'<div class="httplogbar-wrapper noprint',
|
||||
'<div id="forumcomments'
|
||||
) as $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="', '"');
|
||||
|
||||
return $contents;
|
||||
}
|
||||
|
||||
// Extracts the author from an article or element
|
||||
function ExtractAuthor($article){
|
||||
$article_author = $article->find('span.author', 0);
|
||||
if($article_author){
|
||||
return trim(str_replace(', Futura-Sciences', '', $article_author->plaintext));
|
||||
}
|
||||
return '';
|
||||
}
|
||||
}
|
124
bridges/GBAtempBridge.php
Normal file
124
bridges/GBAtempBridge.php
Normal file
@@ -0,0 +1,124 @@
|
||||
<?php
|
||||
class GBAtempBridge extends BridgeAbstract {
|
||||
|
||||
const MAINTAINER = 'ORelio';
|
||||
const NAME = 'GBAtemp';
|
||||
const URI = 'http://gbatemp.net/';
|
||||
const DESCRIPTION = 'GBAtemp is a user friendly underground video game community.';
|
||||
|
||||
const PARAMETERS = array( array(
|
||||
'type'=>array(
|
||||
'name'=>'Type',
|
||||
'type'=>'list',
|
||||
'required'=>true,
|
||||
'values'=>array(
|
||||
'News'=>'N',
|
||||
'Reviews'=>'R',
|
||||
'Tutorials'=>'T',
|
||||
'Forum'=>'F'
|
||||
)
|
||||
)
|
||||
));
|
||||
|
||||
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) {
|
||||
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) {
|
||||
$item = array();
|
||||
$item['uri'] = $uri;
|
||||
$item['title'] = $title;
|
||||
$item['author'] = $author;
|
||||
$item['timestamp'] = $timestamp;
|
||||
$item['content'] = $content;
|
||||
return $item;
|
||||
}
|
||||
|
||||
private function cleanup_post_content($content, $site_url) {
|
||||
$content = str_replace(':arrow:', '➤', $content);
|
||||
$content = str_replace('href="attachments/', 'href="'.$site_url.'attachments/', $content);
|
||||
$content = $this->StripWithDelimiters($content, '<script', '</script>');
|
||||
return $content;
|
||||
}
|
||||
|
||||
private function fetch_post_content($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);
|
||||
}
|
||||
|
||||
public function collectData(){
|
||||
|
||||
$html = getSimpleHTMLDOM(self::URI)
|
||||
or returnServerError('Could not request GBAtemp.');
|
||||
|
||||
switch($this->getInput('type')){
|
||||
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="', '"'));
|
||||
$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);
|
||||
}
|
||||
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);
|
||||
$author = $content->find('a.username', 0)->plaintext;
|
||||
$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);
|
||||
}
|
||||
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="', '"'));
|
||||
$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);
|
||||
}
|
||||
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="', '"'));
|
||||
$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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getName() {
|
||||
$type=array_search(
|
||||
$this->getInput('type'),
|
||||
self::PARAMETERS[$this->queriedContext]['type']['values']
|
||||
);
|
||||
return 'GBAtemp '.$type.' Bridge';
|
||||
}
|
||||
}
|
21
bridges/GelbooruBridge.php
Normal file
21
bridges/GelbooruBridge.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
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 PATHTODATA='.thumb';
|
||||
const IDATTRIBUTE='id';
|
||||
|
||||
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:'')
|
||||
.'&tags='.urlencode($this->getInput('t'));
|
||||
}
|
||||
}
|
71
bridges/GiphyBridge.php
Normal file
71
bridges/GiphyBridge.php
Normal file
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
define('GIPHY_LIMIT', 10);
|
||||
|
||||
class GiphyBridge extends BridgeAbstract{
|
||||
|
||||
const MAINTAINER = "kraoc";
|
||||
const NAME = "Giphy Bridge";
|
||||
const URI = "http://giphy.com/";
|
||||
const CACHE_TIMEOUT = 300; //5min
|
||||
const DESCRIPTION = "Bridge for giphy.com";
|
||||
|
||||
const PARAMETERS = array( array(
|
||||
's'=>array(
|
||||
'name'=>'search tag',
|
||||
'required'=>true
|
||||
),
|
||||
'n'=>array(
|
||||
'name'=>'max number of returned items',
|
||||
'type'=>'number'
|
||||
)
|
||||
));
|
||||
|
||||
public function collectData(){
|
||||
$html = '';
|
||||
$base_url = 'http://giphy.com';
|
||||
$html = getSimpleHTMLDOM(self::URI.'/search/'.urlencode($this->getInput('s').'/'))
|
||||
or returnServerError('No results for this query.');
|
||||
|
||||
$max = GIPHY_LIMIT;
|
||||
if ($this->getInput('n')) {
|
||||
$max = $this->getInput('n');
|
||||
}
|
||||
|
||||
$limit = 0;
|
||||
$kw = urlencode($this->getInput('s'));
|
||||
foreach($html->find('div.hoverable-gif') as $entry) {
|
||||
if($limit < $max) {
|
||||
$node = $entry->first_child();
|
||||
$href = $node->getAttribute('href');
|
||||
|
||||
$html2 = getSimpleHTMLDOM(self::URI . $href)
|
||||
or returnServerError('No results for this query.');
|
||||
$figure = $html2->getElementByTagName('figure');
|
||||
$img = $figure->firstChild();
|
||||
$caption = $figure->lastChild();
|
||||
|
||||
$item = array();
|
||||
$item['id'] = $img->getAttribute('data-gif_id');
|
||||
$item['uri'] = $img->getAttribute('data-bitly_gif_url');
|
||||
$item['username'] = 'Giphy - '.ucfirst($kw);
|
||||
$title = $caption->innertext();
|
||||
$title = preg_replace('/\s+/', ' ',$title);
|
||||
$title = str_replace('animated GIF', '', $title);
|
||||
$title = str_replace($kw, '', $title);
|
||||
$title = preg_replace('/\s+/', ' ',$title);
|
||||
$title = trim($title);
|
||||
if (strlen($title) <= 0) {
|
||||
$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>';
|
||||
|
||||
$this->items[] = $item;
|
||||
$limit++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
190
bridges/GithubIssueBridge.php
Normal file
190
bridges/GithubIssueBridge.php
Normal file
@@ -0,0 +1,190 @@
|
||||
<?php
|
||||
class GithubIssueBridge extends BridgeAbstract{
|
||||
|
||||
const MAINTAINER = 'Pierre Mazière';
|
||||
const NAME = 'Github Issue';
|
||||
const URI = 'https://github.com/';
|
||||
const CACHE_TIMEOUT = 600; // 10min
|
||||
const DESCRIPTION = 'Returns the issues or comments of an issue of a github project';
|
||||
|
||||
const PARAMETERS=array(
|
||||
'global'=>array (
|
||||
'u'=>array(
|
||||
'name'=>'User name',
|
||||
'required'=>true
|
||||
),
|
||||
'p'=>array(
|
||||
'name'=>'Project name',
|
||||
'required'=>true
|
||||
)
|
||||
),
|
||||
|
||||
'Project Issues'=>array(
|
||||
'c'=>array(
|
||||
'name'=>'Show Issues Comments',
|
||||
'type'=>'checkbox'
|
||||
)
|
||||
),
|
||||
'Issue comments'=>array(
|
||||
'i'=>array(
|
||||
'name'=>'Issue number',
|
||||
'type'=>'number',
|
||||
'required'=>'true'
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
public function getName(){
|
||||
$name=$this->getInput('u').'/'.$this->getInput('p');
|
||||
switch($this->queriedContext){
|
||||
case 'Project Issues':
|
||||
if($this->getInput('c')){
|
||||
$prefix=static::NAME.'s comments for ';
|
||||
}else{
|
||||
$prefix=static::NAME.'s for ';
|
||||
}
|
||||
$name=$prefix.$name;
|
||||
break;
|
||||
case 'Issue comments':
|
||||
$name=static::NAME.' '.$name.' #'.$this->getInput('i');
|
||||
break;
|
||||
}
|
||||
return $name;
|
||||
}
|
||||
|
||||
public function getURI(){
|
||||
$uri = static::URI.$this->getInput('u').'/'.$this->getInput('p').'/issues';
|
||||
if($this->queriedContext==='Issue comments'){
|
||||
$uri.='/'.$this->getInput('i');
|
||||
}else if($this->getInput('c')){
|
||||
$uri.='?q=is%3Aissue+sort%3Aupdated-desc';
|
||||
}
|
||||
return $uri;
|
||||
}
|
||||
|
||||
protected function extractIssueComment($issueNbr,$title,$comment){
|
||||
$class=$comment->getAttribute('class');
|
||||
$classes=explode(' ',$class);
|
||||
$event=false;
|
||||
if(in_array('discussion-item',$classes)){
|
||||
$event=true;
|
||||
}
|
||||
|
||||
$author='unknown';
|
||||
if($comment->find('.author',0)){
|
||||
$author=$comment->find('.author',0)->plaintext;
|
||||
}
|
||||
|
||||
$uri=static::URI.$this->getInput('u').'/'.$this->getInput('p').'/issues/'
|
||||
.$issueNbr;
|
||||
|
||||
$comment=$comment->firstChild();
|
||||
if(!$event){
|
||||
$comment=$comment->nextSibling();
|
||||
}
|
||||
|
||||
if($event){
|
||||
$title.=' / '.substr($class,strpos($class,'discussion-item-')+strlen('discussion-item-'));
|
||||
if(!$comment->hasAttribute('id')){
|
||||
$items=array();
|
||||
$timestamp=strtotime($comment->find('relative-time',0)->getAttribute('datetime'));
|
||||
$content=$comment->innertext;
|
||||
while($comment=$comment->nextSibling()){
|
||||
$item=array();
|
||||
$item['author']=$author;
|
||||
$item['title']=html_entity_decode($title,ENT_QUOTES,'UTF-8');
|
||||
$item['timestamp']=$timestamp;
|
||||
$item['content']=$content.'<p>'.$comment->children(1)->innertext.'</p>';
|
||||
$item['uri']=$uri.'#'.$comment->children(1)->getAttribute('id');
|
||||
$items[]=$item;
|
||||
}
|
||||
return $items;
|
||||
}
|
||||
$content=$comment->parent()->innertext;
|
||||
}else{
|
||||
$title.=' / '.trim($comment->firstChild()->plaintext);
|
||||
$content="<pre>".$comment->find('.comment-body',0)->innertext."</pre>";
|
||||
}
|
||||
|
||||
$item = array();
|
||||
$item['author']=$author;
|
||||
$item['uri']= $uri.'#'.$comment->getAttribute('id');
|
||||
$item['title']=html_entity_decode($title,ENT_QUOTES,'UTF-8');
|
||||
$item['timestamp']=strtotime($comment->find('relative-time',0)->getAttribute('datetime'));
|
||||
$item['content']=$content;
|
||||
return $item;
|
||||
}
|
||||
|
||||
protected function extractIssueComments($issue){
|
||||
$items=array();
|
||||
$title=$issue->find('.gh-header-title',0)->plaintext;
|
||||
$issueNbr=trim(substr($issue->find('.gh-header-number',0)->plaintext,1));
|
||||
$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)
|
||||
){
|
||||
$item=$this->extractIssueComment($issueNbr,$title,$comment);
|
||||
if(array_keys($item)!==range(0,count($item)-1)){
|
||||
$item=array($item);
|
||||
}
|
||||
$items=array_merge($items,$item);
|
||||
}
|
||||
}
|
||||
return $items;
|
||||
}
|
||||
|
||||
public function collectData(){
|
||||
$html = getSimpleHTMLDOM($this->getURI())
|
||||
or returnServerError('No results for Github Issue '.$this->getURI());
|
||||
|
||||
switch($this->queriedContext){
|
||||
case 'Issue comments':
|
||||
$this->items=$this->extractIssueComments($html);
|
||||
break;
|
||||
case 'Project Issues':
|
||||
foreach($html->find('.js-active-navigation-container .js-navigation-item') as $issue){
|
||||
$info=$issue->find('.opened-by',0);
|
||||
$issueNbr=substr(trim($info->plaintext),1,strpos(trim($info->plaintext),' '));
|
||||
|
||||
$item=array();
|
||||
$item['content']='';
|
||||
|
||||
if($this->getInput('c')){
|
||||
$uri=static::URI.$this->getInput('u').'/'.$this->getInput('p').'/issues/'.$issueNbr;
|
||||
$issue=getSimpleHTMLDOMCached($uri,static::CACHE_TIMEOUT);
|
||||
if($issue){
|
||||
$this->items=array_merge($this->items,$this->extractIssueComments($issue));
|
||||
continue;
|
||||
}
|
||||
$item['content']='Can not extract comments from '.$uri;
|
||||
}
|
||||
|
||||
$item['author']=$info->find('a',0)->plaintext;
|
||||
$item['timestamp']=strtotime($info->find('relative-time',0)->getAttribute('datetime'));
|
||||
$item['title']=html_entity_decode(
|
||||
$issue->find('.js-navigation-open',0)->plaintext,
|
||||
ENT_QUOTES,
|
||||
'UTF-8'
|
||||
);
|
||||
$comments=$issue->find('.col-5',0)->plaintext;
|
||||
$item['content'].="\n".'Comments: '.($comments?$comments:'0');
|
||||
$item['uri']=self::URI.$issue->find('.js-navigation-open',0)->getAttribute('href');
|
||||
$this->items[]=$item;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
array_walk($this->items, function(&$item){
|
||||
$item['content']=preg_replace('/\s+/',' ',$item['content']);
|
||||
$item['content']=str_replace('href="/','href="'.static::URI,$item['content']);
|
||||
$item['content']=str_replace(
|
||||
'href="#',
|
||||
'href="'.substr($item['uri'],0,strpos($item['uri'],'#')+1),
|
||||
$item['content']
|
||||
);
|
||||
$item['title']=preg_replace('/\s+/',' ',$item['title']);
|
||||
});
|
||||
}
|
||||
}
|
32
bridges/GizmodoBridge.php
Normal file
32
bridges/GizmodoBridge.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
class GizmodoBridge extends FeedExpander {
|
||||
|
||||
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).";
|
||||
|
||||
protected function parseItem($item){
|
||||
$item = parent::parseItem($item);
|
||||
|
||||
$articleHTMLContent = getSimpleHTMLDOMCached($item['uri']);
|
||||
if(!$articleHTMLContent){
|
||||
$text = 'Could not load '.$item['uri'];
|
||||
}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 = strip_tags($text, '<p><b><a><blockquote><img><em>');
|
||||
}
|
||||
|
||||
$item['content'] = $text;
|
||||
return $item;
|
||||
}
|
||||
|
||||
public function collectData(){
|
||||
$this->collectExpandableDatas('http://feeds.gawker.com/gizmodo/full');
|
||||
}
|
||||
}
|
113
bridges/GooglePlusPostBridge.php
Normal file
113
bridges/GooglePlusPostBridge.php
Normal file
@@ -0,0 +1,113 @@
|
||||
<?php
|
||||
class GooglePlusPostBridge extends BridgeAbstract
|
||||
{
|
||||
protected $_title;
|
||||
protected $_url;
|
||||
|
||||
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 PARAMETERS = array( array(
|
||||
'username'=>array(
|
||||
'name'=>'username or Id',
|
||||
'required'=>true
|
||||
)
|
||||
));
|
||||
|
||||
public function collectData()
|
||||
{
|
||||
// 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.');
|
||||
|
||||
// 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');
|
||||
|
||||
// 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)
|
||||
{
|
||||
$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;
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
$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>';
|
||||
|
||||
$content = $post->find('div.Al', 0);
|
||||
|
||||
// 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)
|
||||
{
|
||||
$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))
|
||||
{
|
||||
// skipp bad link, for some hashtag or other stuff
|
||||
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>';
|
||||
|
||||
// extract plaintext
|
||||
$item['content_simple'] = $post->find('div.Al', 0)->plaintext;
|
||||
}
|
||||
|
||||
// $html->save(__DIR__ . '/../posts2.html');
|
||||
}
|
||||
|
||||
public function getName()
|
||||
{
|
||||
return $this->_title ?: 'Google Plus Post Bridge';
|
||||
}
|
||||
|
||||
public function getURI()
|
||||
{
|
||||
return $this->_url ?: self::URI;
|
||||
}
|
||||
}
|
@@ -1,51 +1,54 @@
|
||||
<?php
|
||||
/**
|
||||
* RssBridgeGoogleMostRecent
|
||||
* Search Google for most recent pages regarding a specific topic.
|
||||
* Returns the 100 most recent links in results in past year, sorting by date (most recent first).
|
||||
* Example:
|
||||
* http://www.google.com/search?q=sebsauvage&num=100&complete=0&tbs=qdr:y,sbd:1
|
||||
* complete=0&num=100 : get 100 results
|
||||
* qdr:y : in past year
|
||||
* sbd:1 : sort by date (will only work if qdr: is specified)
|
||||
*
|
||||
* @name Google search
|
||||
* @description Returns most recent results from Google search.
|
||||
* @use1(q="keyword")
|
||||
*/
|
||||
class GoogleSearchBridge extends BridgeAbstract{
|
||||
|
||||
public function collectData(array $param){
|
||||
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 PARAMETERS = array( array(
|
||||
'q'=>array(
|
||||
'name'=>"keyword",
|
||||
'required'=>true
|
||||
)
|
||||
));
|
||||
|
||||
|
||||
public function collectData(){
|
||||
$html = '';
|
||||
|
||||
if (isset($param['q'])) { /* keyword search mode */
|
||||
$html = file_get_html('http://www.google.com/search?q=' . urlencode($param['q']) . '&num=100&complete=0&tbs=qdr:y,sbd:1') or $this->returnError('No results for this query.', 404);
|
||||
}
|
||||
else{
|
||||
$this->returnError('You must specify a keyword (?q=...).', 400);
|
||||
}
|
||||
$html = getSimpleHTMLDOM(self::URI
|
||||
.'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) {
|
||||
$item = new \Item();
|
||||
$item->uri = $element->find('a[href]',0)->href;
|
||||
$item->title = $element->find('h3',0)->plaintext;
|
||||
$item->content = $element->find('span[class=st]',0)->plaintext;
|
||||
$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']; }
|
||||
$item['title'] = $element->find('h3',0)->plaintext;
|
||||
$item['content'] = $element->find('span[class=st]',0)->plaintext;
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return 'Google search';
|
||||
}
|
||||
|
||||
public function getURI(){
|
||||
return 'http://google.com';
|
||||
}
|
||||
|
||||
public function getCacheDuration(){
|
||||
return 1800; // 30 minutes
|
||||
return $this->getInput('q') .' - Google search';
|
||||
}
|
||||
}
|
62
bridges/HDWallpapersBridge.php
Normal file
62
bridges/HDWallpapersBridge.php
Normal file
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
class HDWallpapersBridge extends BridgeAbstract {
|
||||
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 PARAMETERS = array( array(
|
||||
'c'=>array(
|
||||
'name'=>'category',
|
||||
'defaultValue'=>'latest_wallpapers'
|
||||
),
|
||||
'm'=>array('name'=>'max number of wallpapers'),
|
||||
'r'=>array(
|
||||
'name'=>'resolution',
|
||||
'defaultValue'=>'1920x1200',
|
||||
'exampleValue'=>'1920x1200, 1680x1050,…'
|
||||
)
|
||||
));
|
||||
|
||||
public function collectData(){
|
||||
$category = $this->category;
|
||||
if (strrpos($category, 'wallpapers') !== strlen($category)-strlen('wallpapers')) {
|
||||
$category .= '-desktop-wallpapers';
|
||||
}
|
||||
|
||||
$num = 0;
|
||||
$max = $this->getInput('m') ?: 14;
|
||||
$lastpage = 1;
|
||||
|
||||
for ($page = 1; $page <= $lastpage; $page++) {
|
||||
$link = self::URI.'/'.$category.'/page/'.$page;
|
||||
$html = getSimpleHTMLDOM($link) or returnServerError('No results for this query.');
|
||||
|
||||
if ($page === 1) {
|
||||
preg_match('/page\/(\d+)$/', $html->find('.pagination a', -2)->href, $matches);
|
||||
$lastpage = min($matches[1], ceil($max/14));
|
||||
}
|
||||
|
||||
foreach($html->find('.wallpapers .wall a') as $element) {
|
||||
$thumbnail = $element->find('img', 0);
|
||||
|
||||
$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['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>';
|
||||
$this->items[] = $item;
|
||||
|
||||
$num++;
|
||||
if ($num >= $max)
|
||||
break 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return 'HDWallpapers - '.str_replace(['__', '_'], [' & ', ' '], $this->getInput('c')).' ['.$this->getInput('r').']';
|
||||
}
|
||||
}
|
23
bridges/HentaiHavenBridge.php
Normal file
23
bridges/HentaiHavenBridge.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
class HentaiHavenBridge extends BridgeAbstract{
|
||||
|
||||
const MAINTAINER = "albirew";
|
||||
const NAME = "Hentai Haven";
|
||||
const URI = "http://hentaihaven.org/";
|
||||
const CACHE_TIMEOUT = 21600; // 6h
|
||||
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['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;
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
}
|
38
bridges/IdenticaBridge.php
Normal file
38
bridges/IdenticaBridge.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
class IdenticaBridge extends BridgeAbstract{
|
||||
|
||||
const MAINTAINER = "mitsukarenai";
|
||||
const NAME = "Identica Bridge";
|
||||
const URI = "https://identi.ca/";
|
||||
const CACHE_TIMEOUT = 300; // 5min
|
||||
const DESCRIPTION = "Returns user timelines";
|
||||
|
||||
const PARAMETERS = array( array(
|
||||
'u'=>array(
|
||||
'name'=>'username',
|
||||
'required'=>true
|
||||
)
|
||||
));
|
||||
|
||||
public function collectData(){
|
||||
$html = getSimpleHTMLDOM($this->getURI())
|
||||
or returnServerError('Requested username can\'t be found.');
|
||||
|
||||
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
|
||||
$item['title'] = $this->getInput('u') . ' | ' . $item['content'];
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return $this->getInput('u') .' - Identica Bridge';
|
||||
}
|
||||
|
||||
public function getURI(){
|
||||
return self::URI.urlencode($this->getInput('u'));
|
||||
}
|
||||
}
|
71
bridges/InstagramBridge.php
Normal file
71
bridges/InstagramBridge.php
Normal file
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
class InstagramBridge extends BridgeAbstract{
|
||||
|
||||
const MAINTAINER = "pauder";
|
||||
const NAME = "Instagram Bridge";
|
||||
const URI = "http://instagram.com/";
|
||||
const DESCRIPTION = "Returns the newest images";
|
||||
|
||||
const PARAMETERS = array( array(
|
||||
'u'=>array(
|
||||
'name'=>'username',
|
||||
'required'=>true
|
||||
)
|
||||
));
|
||||
|
||||
public function collectData(){
|
||||
$html = getSimpleHTMLDOM($this->getURI())
|
||||
or returnServerError('Could not request Instagram.');
|
||||
|
||||
$innertext = null;
|
||||
|
||||
foreach($html->find('script') as $script)
|
||||
{
|
||||
if ('' === $script->innertext) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$pos = strpos(trim($script->innertext), 'window._sharedData');
|
||||
if (0 !== $pos)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$innertext = $script->innertext;
|
||||
break;
|
||||
}
|
||||
|
||||
$json = trim(substr($innertext, $pos+18), ' =;');
|
||||
$data = json_decode($json);
|
||||
|
||||
|
||||
|
||||
$userMedia = $data->entry_data->ProfilePage[0]->user->media->nodes;
|
||||
|
||||
foreach($userMedia as $media)
|
||||
{
|
||||
|
||||
$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;
|
||||
} else {
|
||||
$item['title'] = basename($media->display_src);
|
||||
}
|
||||
$item['timestamp'] = $media->date;
|
||||
$this->items[] = $item;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return $this->getInput('u') .' - Instagram Bridge';
|
||||
}
|
||||
|
||||
public function getURI(){
|
||||
return self::URI.urlencode($this->getInput('u'));
|
||||
}
|
||||
}
|
||||
|
468
bridges/IsoHuntBridge.php
Normal file
468
bridges/IsoHuntBridge.php
Normal file
@@ -0,0 +1,468 @@
|
||||
<?php
|
||||
class IsoHuntBridge extends BridgeAbstract{
|
||||
const MAINTAINER = 'logmanoriginal';
|
||||
const NAME = 'isoHunt Bridge';
|
||||
const URI = 'https://isohunt.to/';
|
||||
const CACHE_TIMEOUT = 300; //5min
|
||||
const DESCRIPTION = 'Returns the latest results by category or search result';
|
||||
|
||||
const PARAMETERS = array(
|
||||
/*
|
||||
* Get feeds for one of the "latest" categories
|
||||
* Notice: The categories "News" and "Top Searches" are received from the main page
|
||||
* Elements are sorted by name ascending!
|
||||
*/
|
||||
'By "Latest" category' => array(
|
||||
'latest_category'=>array(
|
||||
'name'=>'Latest category',
|
||||
'type'=>'list',
|
||||
'required'=>true,
|
||||
'title'=>'Select your category',
|
||||
'defaultValue'=>'news',
|
||||
'values'=>array(
|
||||
'Hot Torrents'=>'hot_torrents',
|
||||
'News'=>'news',
|
||||
'Releases'=>'releases',
|
||||
'Torrents'=>'torrents'
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
/*
|
||||
* Get feeds for one of the "torrent" categories
|
||||
* Make sure to add new categories also to get_torrent_category_index($)!
|
||||
* Elements are sorted by name ascending!
|
||||
*/
|
||||
'By "Torrent" category' => array(
|
||||
'torrent_category'=>array(
|
||||
'name'=>'Torrent category',
|
||||
'type'=>'list',
|
||||
'required'=>true,
|
||||
'title'=>'Select your category',
|
||||
'defaultValue'=>'anime',
|
||||
'values'=>array(
|
||||
'Adult'=>'adult',
|
||||
'Anime'=>'anime',
|
||||
'Books'=>'books',
|
||||
'Games'=>'games',
|
||||
'Movies'=>'movies',
|
||||
'Music'=>'music',
|
||||
'Other'=>'other',
|
||||
'Series & TV'=>'series_tv',
|
||||
'Software'=>'software'
|
||||
)
|
||||
),
|
||||
'torrent_popularity'=>array(
|
||||
'name'=>'Sort by popularity',
|
||||
'type'=>'checkbox',
|
||||
'title'=>'Activate to receive results by popularity'
|
||||
)
|
||||
),
|
||||
|
||||
/*
|
||||
* Get feeds for a specific search request
|
||||
*/
|
||||
'Search torrent by name' => array(
|
||||
'search_name'=>array(
|
||||
'name'=>'Name',
|
||||
'required'=>true,
|
||||
'title'=>'Insert your search query',
|
||||
'exampleValue'=>'Bridge'
|
||||
),
|
||||
'search_category'=>array(
|
||||
'name'=>'Category',
|
||||
'type'=>'list',
|
||||
'title'=>'Select your category',
|
||||
'defaultValue'=>'all',
|
||||
'values'=>array(
|
||||
'Adult'=>'adult',
|
||||
'All'=>'all',
|
||||
'Anime'=>'anime',
|
||||
'Books'=>'books',
|
||||
'Games'=>'games',
|
||||
'Movies'=>'movies',
|
||||
'Music'=>'music',
|
||||
'Other'=>'other',
|
||||
'Series & TV'=>'series_tv',
|
||||
'Software'=>'software'
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
public function getURI(){
|
||||
$uri=self::URI;
|
||||
switch($this->queriedContext){
|
||||
case 'By "Latest" category':
|
||||
switch($this->getInput('latest_category')){
|
||||
case 'hot_torrents':
|
||||
$uri .= 'statistic/hot/torrents';
|
||||
break;
|
||||
case 'news':
|
||||
break;
|
||||
case 'releases':
|
||||
$uri .= 'releases.php';
|
||||
break;
|
||||
case 'torrents':
|
||||
$uri .= 'latest.php';
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'By "Torrent" category':
|
||||
$uri .= $this->build_category_uri(
|
||||
$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);
|
||||
if($category!=='movies')
|
||||
$uri .= '&ihq=' . urlencode($this->getInput('search_name'));
|
||||
break;
|
||||
}
|
||||
|
||||
return $uri;
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
switch($this->queriedContext){
|
||||
case 'By "Latest" category':
|
||||
$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(
|
||||
$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(
|
||||
$this->getInput('search_category'),
|
||||
self::PARAMETERS['Search torrent by name']['search_category']['values']
|
||||
);
|
||||
$name = 'Search: "' . $this->getInput('search_name') . '" in category: ' . $categoryName . ' - ' . self::NAME;
|
||||
break;
|
||||
}
|
||||
|
||||
return $name;
|
||||
}
|
||||
|
||||
|
||||
public function collectData(){
|
||||
$html = $this->load_html($this->getURI());
|
||||
|
||||
switch($this->queriedContext){
|
||||
case 'By "Latest" category':
|
||||
switch($this->getInput('latest_category')){
|
||||
case 'hot_torrents':
|
||||
$this->get_latest_hot_torrents($html);
|
||||
break;
|
||||
case 'news':
|
||||
$this->get_latest_news($html);
|
||||
break;
|
||||
case 'releases':
|
||||
case 'torrents':
|
||||
$this->get_latest_torrents($html);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'By "Torrent" category':
|
||||
if($this->getInput('torrent_category') === 'movies'){
|
||||
// This one is special (content wise)
|
||||
$this->get_movie_torrents($html);
|
||||
}else{
|
||||
$this->get_latest_torrents($html);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'Search torrent by name':
|
||||
if( $this->getInput('search_category') === 'movies'){
|
||||
// This one is special (content wise)
|
||||
$this->get_movie_torrents($html);
|
||||
} else {
|
||||
$this->get_latest_torrents($html);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#region Helper functions for "Movie Torrents"
|
||||
|
||||
private function get_movie_torrents($html){
|
||||
$container = $html->find('div#w0', 0);
|
||||
if(!$container)
|
||||
returnServerError('Unable to find torrent container!');
|
||||
|
||||
$torrents = $container->find('article');
|
||||
if(!$torrents)
|
||||
returnServerError('Unable to find torrents!');
|
||||
|
||||
foreach($torrents as $torrent){
|
||||
|
||||
$anchor = $torrent->find('a', 0);
|
||||
if(!$anchor)
|
||||
returnServerError('Unable to find anchor!');
|
||||
|
||||
$date = $torrent->find('small', 0);
|
||||
if(!$date)
|
||||
returnServerError('Unable to find date!');
|
||||
|
||||
$item = array();
|
||||
|
||||
$item['uri'] = $this->fix_relative_uri($anchor->href);
|
||||
$item['title'] = $anchor->title;
|
||||
// $item['author'] =
|
||||
$item['timestamp'] = strtotime($date->plaintext);
|
||||
$item['content'] = $this->fix_relative_uri($torrent->innertext);
|
||||
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Helper functions for "Latest Hot Torrents"
|
||||
|
||||
private function get_latest_hot_torrents($html){
|
||||
$container = $html->find('div#serps', 0);
|
||||
if(!$container)
|
||||
returnServerError('Unable to find torrent container!');
|
||||
|
||||
$torrents = $container->find('tr');
|
||||
if(!$torrents)
|
||||
returnServerError('Unable to find torrents!');
|
||||
|
||||
// Remove first element (header row)
|
||||
$torrents = array_slice($torrents, 1);
|
||||
|
||||
foreach($torrents as $torrent){
|
||||
|
||||
$cell = $torrent->find('td', 0);
|
||||
if(!$cell)
|
||||
returnServerError('Unable to find cell!');
|
||||
|
||||
$element = $cell->find('a', 0);
|
||||
if(!$element)
|
||||
returnServerError('Unable to find element!');
|
||||
|
||||
$item = array();
|
||||
|
||||
$item['uri'] = $element->href;
|
||||
$item['title'] = $element->plaintext;
|
||||
// $item['author'] =
|
||||
// $item['timestamp'] =
|
||||
// $item['content'] =
|
||||
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Helper functions for "Latest News"
|
||||
|
||||
private function get_latest_news($html){
|
||||
$container = $html->find('div#postcontainer', 0);
|
||||
if(!$container)
|
||||
returnServerError('Unable to find post container!');
|
||||
|
||||
$posts = $container->find('div.index-post');
|
||||
if(!$posts)
|
||||
returnServerError('Unable to find posts!');
|
||||
|
||||
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);
|
||||
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
private function latest_news_extract_author($post){
|
||||
$author = $post->find('small', 0);
|
||||
if(!$author)
|
||||
returnServerError('Unable to find author!');
|
||||
|
||||
// The author is hidden within a string like: 'Posted by {author} on {date}'
|
||||
preg_match('/Posted\sby\s(.*)\son/i', $author->innertext, $matches);
|
||||
|
||||
return $matches[1];
|
||||
}
|
||||
|
||||
private function latest_news_extract_timestamp($post){
|
||||
$date = $post->find('small', 0);
|
||||
if(!$date)
|
||||
returnServerError('Unable to find date!');
|
||||
|
||||
// The date is hidden within a string like: 'Posted by {author} on {date}'
|
||||
preg_match('/Posted\sby\s.*\son\s(.*)/i', $date->innertext, $matches);
|
||||
|
||||
$timestamp = strtotime($matches[1]);
|
||||
|
||||
// Make sure date is not in the future (dates are given like 'Nov. 20' without year)
|
||||
if($timestamp > time()){
|
||||
$timestamp = strtotime('-1 year', $timestamp);
|
||||
}
|
||||
|
||||
return $timestamp;
|
||||
}
|
||||
|
||||
private function latest_news_extract_title($post){
|
||||
$title = $post->find('a', 0);
|
||||
if(!$title)
|
||||
returnServerError('Unable to find title!');
|
||||
|
||||
return $title->plaintext;
|
||||
}
|
||||
|
||||
private function latest_news_extract_uri($post){
|
||||
$uri = $post->find('a', 0);
|
||||
if(!$uri)
|
||||
returnServerError('Unable to find uri!');
|
||||
|
||||
return $uri->href;
|
||||
}
|
||||
|
||||
private function latest_news_extract_content($post){
|
||||
$content = $post->find('div', 0);
|
||||
if(!$content)
|
||||
returnServerError('Unable to find content!');
|
||||
|
||||
// Remove <h2>...</h2> (title)
|
||||
foreach($content->find('h2') as $element){
|
||||
$element->outertext = '';
|
||||
}
|
||||
|
||||
// Remove <small>...</small> (author)
|
||||
foreach($content->find('small') as $element){
|
||||
$element->outertext = '';
|
||||
}
|
||||
|
||||
return $content->innertext;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Helper functions for "Latest Torrents", "Latest Releases" and "Torrent Category"
|
||||
|
||||
private function get_latest_torrents($html){
|
||||
$container = $html->find('div#serps', 0);
|
||||
if(!$container)
|
||||
returnServerError('Unable to find torrent container!');
|
||||
|
||||
$torrents = $container->find('tr[data-key]');
|
||||
if(!$torrents)
|
||||
returnServerError('Unable to find torrents!');
|
||||
|
||||
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['content'] = ''; // There is no valuable content
|
||||
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
private function latest_torrents_extract_title($torrent){
|
||||
$cell = $torrent->find('td.title-row', 0);
|
||||
if(!$cell)
|
||||
returnServerError('Unable to find title cell!');
|
||||
|
||||
$title = $cell->find('span', 0);
|
||||
if(!$title)
|
||||
returnServerError('Unable to find title!');
|
||||
|
||||
return $title->plaintext;
|
||||
}
|
||||
|
||||
private function latest_torrents_extract_uri($torrent){
|
||||
$cell = $torrent->find('td.title-row', 0);
|
||||
if(!$cell)
|
||||
returnServerError('Unable to find title cell!');
|
||||
|
||||
$uri = $cell->find('a', 0);
|
||||
if(!$uri)
|
||||
returnServerError('Unable to find uri!');
|
||||
|
||||
return $this->fix_relative_uri($uri->href);
|
||||
}
|
||||
|
||||
private function latest_torrents_extract_author($torrent){
|
||||
$cell = $torrent->find('td.user-row', 0);
|
||||
if(!$cell)
|
||||
return; // No author
|
||||
|
||||
$user = $cell->find('a', 0);
|
||||
if(!$user)
|
||||
returnServerError('Unable to find user!');
|
||||
|
||||
return $user->plaintext;
|
||||
}
|
||||
|
||||
private function latest_torrents_extract_timestamp($torrent){
|
||||
$cell = $torrent->find('td.date-row', 0);
|
||||
if(!$cell)
|
||||
returnServerError('Unable to find date cell!');
|
||||
|
||||
return strtotime('-' . $cell->plaintext, time());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Generic helper functions
|
||||
|
||||
private function load_html($uri){
|
||||
$html = getSimpleHTMLDOM($uri);
|
||||
if(!$html)
|
||||
returnServerError('Unable to load ' . $uri . '!');
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
private function fix_relative_uri($uri){
|
||||
return preg_replace('/\//i', self::URI, $uri, 1);
|
||||
}
|
||||
|
||||
private function build_category_uri($category, $order_popularity = false){
|
||||
switch($category){
|
||||
case 'anime': $index = 1; break;
|
||||
case 'software' : $index = 2; break;
|
||||
case 'games' : $index = 3; break;
|
||||
case 'adult' : $index = 4; break;
|
||||
case 'movies' : $index = 5; break;
|
||||
case 'music' : $index = 6; break;
|
||||
case 'other' : $index = 7; break;
|
||||
case 'series_tv' : $index = 8; break;
|
||||
case 'books': $index = 9; break;
|
||||
case 'all':
|
||||
default: $index = 0; break;
|
||||
}
|
||||
|
||||
return 'torrents/?iht=' . $index . '&ihs=' . ($order_popularity ? 1 : 0) . '&age=0';
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
89
bridges/JapanExpoBridge.php
Normal file
89
bridges/JapanExpoBridge.php
Normal file
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
class JapanExpoBridge extends BridgeAbstract {
|
||||
|
||||
const MAINTAINER = 'Ginko';
|
||||
const NAME = 'Japan Expo Actualités';
|
||||
const URI = 'http://www.japan-expo-paris.com/fr/actualites';
|
||||
const CACHE_TIMEOUT = 14400; // 4h
|
||||
const DESCRIPTION = 'Returns most recent entries from Japan Expo actualités.';
|
||||
const PARAMETERS = array( array(
|
||||
'mode'=>array(
|
||||
'name'=>'Show full contents',
|
||||
'type'=>'checkbox',
|
||||
)
|
||||
));
|
||||
|
||||
public function collectData(){
|
||||
|
||||
function french_pubdate_to_timestamp($date_to_parse) {
|
||||
return strtotime(
|
||||
strtr(
|
||||
strtolower(str_replace('Publié le ', '', $date_to_parse)),
|
||||
array(
|
||||
'janvier' => 'jan',
|
||||
'février' => 'feb',
|
||||
'mars' => 'march',
|
||||
'avril' => 'apr',
|
||||
'mai' => 'may',
|
||||
'juin' => 'jun',
|
||||
'juillet' => 'jul',
|
||||
'août' => 'aug',
|
||||
'septembre' => 'sep',
|
||||
'octobre' => 'oct',
|
||||
'novembre' => 'nov',
|
||||
'décembre' => 'dec'
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$convert_article_images = function ($matches) {
|
||||
if (is_array($matches) && count($matches) > 1) {
|
||||
return '<img src="'.$matches[1].'" />';
|
||||
}
|
||||
};
|
||||
|
||||
$html = getSimpleHTMLDOM(self::URI)
|
||||
or returnServerError('Could not request JapanExpo: '.self::URI);
|
||||
$fullcontent = $this->getInput('mode');
|
||||
$count = 0;
|
||||
|
||||
foreach ($html->find('a._tile2') as $element) {
|
||||
|
||||
$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], "'");
|
||||
|
||||
if ($fullcontent) {
|
||||
if ($count >= 5) {
|
||||
break;
|
||||
}
|
||||
|
||||
$article_html = getSimpleHTMLDOMCached('Could not request JapanExpo: '.$url);
|
||||
$header = $article_html->find('header.pageHeadBox', 0);
|
||||
$timestamp = strtotime($header->find('time', 0)->datetime);
|
||||
$title_html = $header->find('div.section', 0)->next_sibling();
|
||||
$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);
|
||||
$content = $headings.$article;
|
||||
} else {
|
||||
$date_text = $element->find('span.date', 0)->plaintext;
|
||||
$timestamp = french_pubdate_to_timestamp($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>';
|
||||
}
|
||||
|
||||
$item = array();
|
||||
$item['uri'] = $url;
|
||||
$item['title'] = $title;
|
||||
$item['timestamp'] = $timestamp;
|
||||
$item['content'] = $content;
|
||||
$this->items[] = $item;
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
}
|
11
bridges/KonachanBridge.php
Normal file
11
bridges/KonachanBridge.php
Normal file
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
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";
|
||||
|
||||
}
|
22
bridges/KoreusBridge.php
Normal file
22
bridges/KoreusBridge.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<?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)";
|
||||
|
||||
protected function parseItem($item) {
|
||||
$item = parent::parseItem($item);
|
||||
|
||||
$html = getSimpleHTMLDOMCached($item['uri']);
|
||||
$text = $html->find('p.itemText', 0)->innertext;
|
||||
$item['content'] = utf8_encode($text);
|
||||
|
||||
return $item;
|
||||
}
|
||||
|
||||
public function collectData(){
|
||||
$this->collectExpandableDatas('http://feeds.feedburner.com/Koreus-articles');
|
||||
}
|
||||
}
|
236
bridges/KununuBridge.php
Normal file
236
bridges/KununuBridge.php
Normal file
@@ -0,0 +1,236 @@
|
||||
<?php
|
||||
class KununuBridge extends BridgeAbstract {
|
||||
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 PARAMETERS = array(
|
||||
'global' => array(
|
||||
'site'=>array(
|
||||
'name'=>'Site',
|
||||
'type'=>'list',
|
||||
'required'=>true,
|
||||
'title'=>'Select your site',
|
||||
'values'=>array(
|
||||
'Austria'=>'at',
|
||||
'Germany'=>'de',
|
||||
'Switzerland'=>'ch',
|
||||
'United States'=>'us'
|
||||
)
|
||||
),
|
||||
'full'=>array(
|
||||
'name'=>'Load full article',
|
||||
'type'=>'checkbox',
|
||||
'required'=>false,
|
||||
'exampleValue'=>'checked',
|
||||
'title'=>'Activate to load full article'
|
||||
)
|
||||
),
|
||||
|
||||
array(
|
||||
'company'=>array(
|
||||
'name'=>'Company',
|
||||
'required'=>true,
|
||||
'exampleValue'=>'kununu-us',
|
||||
'title'=>'Insert company name (i.e. Kununu US) or URI path (i.e. kununu-us)'
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
private $companyName='';
|
||||
|
||||
public function getURI(){
|
||||
$company = $this->encode_umlauts(strtolower(str_replace(' ', '-', trim($this->getInput('company')))));
|
||||
$site=$this->getInput('site');
|
||||
$section = '';
|
||||
switch($site){
|
||||
case 'at':
|
||||
case 'de':
|
||||
case 'ch':
|
||||
$section = 'kommentare';
|
||||
break;
|
||||
case 'us':
|
||||
$section = 'reviews';
|
||||
break;
|
||||
}
|
||||
|
||||
return self::URI.$site.'/'.$company.'/'.$section;
|
||||
}
|
||||
|
||||
function getName(){
|
||||
$company = $this->encode_umlauts(strtolower(str_replace(' ', '-', trim($this->getInput('company')))));
|
||||
return ($this->companyName?:$company).' - '.self::NAME;
|
||||
}
|
||||
|
||||
public function collectData(){
|
||||
$full = $this->getInput('full');
|
||||
|
||||
// Load page
|
||||
$html = getSimpleHTMLDOM($this->getURI());
|
||||
if(!$html)
|
||||
returnServerError('Unable to receive data from ' . $this->getURI() . '!');
|
||||
// Update name for this request
|
||||
$this->companyName = $this->extract_company_name($html);
|
||||
|
||||
// Find the section with all the panels (reviews)
|
||||
$section = $html->find('section.kununu-scroll-element', 0);
|
||||
if($section === false)
|
||||
returnServerError('Unable to find panel section!');
|
||||
|
||||
// Find all articles (within the panels)
|
||||
$articles = $section->find('article');
|
||||
if($articles === false || empty($articles))
|
||||
returnServerError('Unable to find articles!');
|
||||
|
||||
// Go through all articles
|
||||
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);
|
||||
|
||||
if($full)
|
||||
$item['content'] = $this->extract_full_description($item['uri']);
|
||||
else
|
||||
$item['content'] = $this->extract_article_description($article);
|
||||
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fixes relative URLs in the given text
|
||||
*/
|
||||
private function fix_url($text){
|
||||
return preg_replace('/href=(\'|\")\//i', 'href="'.self::URI, $text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes unmlauts in the given text
|
||||
*/
|
||||
private function encode_umlauts($text){
|
||||
$umlauts = Array("/ä/","/ö/","/ü/","/Ä/","/Ö/","/Ü/","/ß/");
|
||||
$replace = Array("ae","oe","ue","Ae","Oe","Ue","ss");
|
||||
|
||||
return preg_replace($umlauts, $replace, $text);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
returnServerError('Cannot find company name!');
|
||||
|
||||
return $company_name->plaintext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the date from a given article
|
||||
*/
|
||||
private function extract_article_date($article){
|
||||
// They conviniently provide a time attribute for us :)
|
||||
$date = $article->find('time[itemprop=dtreviewed]', 0);
|
||||
if($date === false)
|
||||
returnServerError('Cannot find article date!');
|
||||
|
||||
return strtotime($date->datetime);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the rating from a given article
|
||||
*/
|
||||
private function extract_article_rating($article){
|
||||
$rating = $article->find('span.rating', 0);
|
||||
if($rating === false)
|
||||
returnServerError('Cannot find article rating!');
|
||||
|
||||
return $rating->getAttribute('aria-label');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the summary from a given article
|
||||
*/
|
||||
private function extract_article_summary($article){
|
||||
$summary = $article->find('[itemprop=summary]', 0);
|
||||
if($summary === false)
|
||||
returnServerError('Cannot find article summary!');
|
||||
|
||||
return strip_tags($summary->innertext);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
returnServerError('Cannot find article URI!');
|
||||
|
||||
return self::URI . $anchor->href;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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!');
|
||||
|
||||
// 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;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $author_position;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the description from a given article
|
||||
*/
|
||||
private function extract_article_description($article){
|
||||
$description = $article->find('div[itemprop=description]', 0);
|
||||
if($description === false)
|
||||
returnServerError('Cannot find article description!');
|
||||
|
||||
return $this->fix_url($description->innertext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the full description from a given uri
|
||||
*/
|
||||
private function extract_full_description($uri){
|
||||
// Load full article
|
||||
$html = getSimpleHTMLDOMCached($uri);
|
||||
if($html === false)
|
||||
returnServerError('Could not load full description!');
|
||||
|
||||
// Find the article
|
||||
$article = $html->find('article', 0);
|
||||
if($article === false)
|
||||
returnServerError('Cannot find article!');
|
||||
|
||||
// Luckily they use the same layout for the review overview and full article pages :)
|
||||
return $this->extract_article_description($article);
|
||||
}
|
||||
}
|
144
bridges/LWNprevBridge.php
Normal file
144
bridges/LWNprevBridge.php
Normal file
@@ -0,0 +1,144 @@
|
||||
<?php
|
||||
class LWNprevBridge extends BridgeAbstract{
|
||||
const MAINTAINER = 'Pierre Mazière';
|
||||
const NAME = 'LWN Free Weekly Edition';
|
||||
const URI = 'https://lwn.net/';
|
||||
const CACHE_TIMEOUT = 604800; // 1 week
|
||||
const DESCRIPTION = 'LWN Free Weekly Edition available one week late';
|
||||
|
||||
function getURI(){
|
||||
return self::URI.'free/bigpage';
|
||||
}
|
||||
|
||||
private function jumpToNextTag(&$node){
|
||||
while($node && $node->nodeType===XML_TEXT_NODE){
|
||||
$nextNode=$node->nextSibling;
|
||||
if(!$nextNode){
|
||||
break;
|
||||
}
|
||||
$node=$nextNode;
|
||||
}
|
||||
}
|
||||
|
||||
private function jumpToPreviousTag(&$node){
|
||||
while($node && $node->nodeType===XML_TEXT_NODE){
|
||||
$previousNode=$node->previousSibling;
|
||||
if(!$previousNode){
|
||||
break;
|
||||
}
|
||||
$node=$previousNode;
|
||||
}
|
||||
}
|
||||
|
||||
public function collectData(){
|
||||
// Because the LWN page is written in loose HTML and not XHTML,
|
||||
// Simple HTML Dom is not accurate enough for the job
|
||||
$content=getContents($this->getURI())
|
||||
or returnServerError('No results for LWNprev');
|
||||
|
||||
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 '))
|
||||
);
|
||||
|
||||
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');
|
||||
}else{
|
||||
$item['uri']=$realURI.'#'.$URICounter;
|
||||
}
|
||||
$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;
|
||||
}
|
||||
$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:'').'] ';
|
||||
}
|
||||
$item['title'].=$h2->textContent;
|
||||
|
||||
$node=$h2;
|
||||
$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')))
|
||||
)
|
||||
)
|
||||
){
|
||||
$contentEnd=true;
|
||||
}else{
|
||||
$content.=$node->C14N();
|
||||
}
|
||||
}
|
||||
$item['content']=$content;
|
||||
$this->items[]=$item;
|
||||
}
|
||||
}
|
||||
}
|
186
bridges/LeBonCoinBridge.php
Executable file
186
bridges/LeBonCoinBridge.php
Executable file
@@ -0,0 +1,186 @@
|
||||
<?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 PARAMETERS = array( array(
|
||||
'k'=>array('name'=>'Mot Clé'),
|
||||
'r'=>array(
|
||||
'name'=>'Région',
|
||||
'type'=>'list',
|
||||
'values'=>array(
|
||||
'Toute la France'=>'ile_de_france/occasions',
|
||||
'Alsace'=>'alsace',
|
||||
'Aquitaine'=>'aquitaine',
|
||||
'Auvergne'=>'auvergne',
|
||||
'Basse Normandie'=>'basse_normandie',
|
||||
'Bourgogne'=>'bourgogne',
|
||||
'Bretagne'=>'bretagne',
|
||||
'Centre'=>'centre',
|
||||
'Champagne Ardenne'=>'champagne_ardenne',
|
||||
'Corse'=>'corse',
|
||||
'Franche Comté'=>'franche_comte',
|
||||
'Haute Normandie'=>'haute_normandie',
|
||||
'Ile de France'=>'ile_de_france',
|
||||
'Languedoc Roussillon'=>'languedoc_roussillon',
|
||||
'Limousin'=>'limousin',
|
||||
'Lorraine'=>'lorraine',
|
||||
'Midi Pyrénées'=>'midi_pyrenees',
|
||||
'Nord Pas De Calais'=>'nord_pas_de_calais',
|
||||
'Pays de la Loire'=>'pays_de_la_loire',
|
||||
'Picardie'=>'picardie',
|
||||
'Poitou Charentes'=>'poitou_charentes',
|
||||
'Provence Alpes Côte d\'Azur'=>'provence_alpes_cote_d_azur',
|
||||
'Rhône-Alpes'=>'rhone_alpes',
|
||||
'Guadeloupe'=>'guadeloupe',
|
||||
'Martinique'=>'martinique',
|
||||
'Guyane'=>'guyane',
|
||||
'Réunion'=>'reunion'
|
||||
)
|
||||
),
|
||||
'c'=>array(
|
||||
'name'=>'Catégorie',
|
||||
'type'=>'list',
|
||||
'values'=>array(
|
||||
'TOUS'=>'',
|
||||
'EMPLOI'=>'_emploi_',
|
||||
'VEHICULES'=>array(
|
||||
'Tous'=>'_vehicules_',
|
||||
'Voitures'=>'voitures',
|
||||
'Motos'=>'motos',
|
||||
'Caravaning'=>'caravaning',
|
||||
'Utilitaires'=>'utilitaires',
|
||||
'Équipement Auto'=>'equipement_auto',
|
||||
'Équipement Moto'=>'equipement_moto',
|
||||
'Équipement Caravaning'=>'equipement_caravaning',
|
||||
'Nautisme'=>'nautisme',
|
||||
'Équipement Nautisme'=>'equipement_nautisme'
|
||||
),
|
||||
'IMMOBILIER'=>array(
|
||||
'Tous'=>'_immobilier_',
|
||||
'Ventes immobilières'=>'ventes_immobilieres',
|
||||
'Locations'=>'locations',
|
||||
'Colocations'=>'colocations',
|
||||
'Bureaux & Commerces'=>'bureaux_commerces'
|
||||
),
|
||||
'VACANCES'=>array(
|
||||
'Tous'=>'_vacances_',
|
||||
'Location gîtes'=>'locations_gites',
|
||||
'Chambres d\'hôtes'=>'chambres_d_hotes',
|
||||
'Campings'=>'campings',
|
||||
'Hôtels'=>'hotels',
|
||||
'Hébergements insolites'=>'hebergements_insolites'
|
||||
),
|
||||
'MULTIMEDIA'=>array(
|
||||
'Tous'=>'_multimedia_',
|
||||
'Informatique'=>'informatique',
|
||||
'Consoles & Jeux vidéo'=>'consoles_jeux_video',
|
||||
'Image & Son'=>'image_son',
|
||||
'Téléphonie'=>'telephonie'
|
||||
),
|
||||
'LOISIRS'=>array(
|
||||
'Tous'=>'_loisirs_',
|
||||
'DVD / Films'=>'dvd_films',
|
||||
'CD / Musique'=>'cd_musique',
|
||||
'Livres'=>'livres',
|
||||
'Animaux'=>'animaux',
|
||||
'Vélos'=>'velos',
|
||||
'Sports & Hobbies'=>'sports_hobbies',
|
||||
'Instruments de musique'=>'instruments_de_musique',
|
||||
'Collection'=>'collection',
|
||||
'Jeux & Jouets'=>'jeux_jouets',
|
||||
'Vins & Gastronomie'=>'vins_gastronomie'
|
||||
),
|
||||
'MATÉRIEL PROFESSIONNEL'=>array(
|
||||
'Tous'=>'_materiel_professionnel_',
|
||||
'Matériel Agricole'=>'mateiel_agricole',
|
||||
'Transport - Manutention'=>'transport_manutention',
|
||||
'BTP - Chantier - Gros-œuvre'=>'btp_chantier_gros_oeuvre',
|
||||
'Outillage - Matériaux 2nd-œuvre'=>'outillage_materiaux_2nd_oeuvre',
|
||||
'Équipements Industriels'=>'equipement_industriels',
|
||||
'Restauration - Hôtellerie'=>'restauration_hotellerie',
|
||||
'Fournitures de Bureau'=>'fournitures_de_bureau',
|
||||
'Commerces & Marchés'=>'commerces_marches',
|
||||
'Matériel médical'=>'materiel_medical'
|
||||
),
|
||||
'SERVICES'=>array(
|
||||
'Tous'=>'_services_',
|
||||
'Prestations de services'=>'prestations_de_services',
|
||||
'Billetterie'=>'billetterie',
|
||||
'Évènements'=>'evenements',
|
||||
'Cours particuliers'=>'cours_particuliers',
|
||||
'Covoiturage'=>'covoiturage'
|
||||
),
|
||||
'MAISON'=>array(
|
||||
'Tous'=>'_maison_',
|
||||
'Ameublement'=>'ameublement',
|
||||
'Électroménager'=>'electromenager',
|
||||
'Arts de la table'=>'arts_de_la_table',
|
||||
'Décoration'=>'decoration',
|
||||
'Linge de maison'=>'linge_de_maison',
|
||||
'Bricolage'=>'bricolage',
|
||||
'Jardinage'=>'jardinage',
|
||||
'Vêtements'=>'vetements',
|
||||
'Chaussures'=>'chaussures',
|
||||
'Accessoires & Bagagerie'=>'accessoires_bagagerie',
|
||||
'Montres & Bijoux'=>'montres_bijoux',
|
||||
'Équipement bébé'=>'equipement_bebe',
|
||||
'Vêtements bébé'=>'vetements_bebe'
|
||||
),
|
||||
'AUTRES'=>'autres'
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
public function collectData(){
|
||||
|
||||
$category=$this->getInput('c');
|
||||
if (empty($category)){
|
||||
$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.');
|
||||
|
||||
$list = $html->find('.tabsContent', 0);
|
||||
if($list === NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
$tags = $list->find('li');
|
||||
|
||||
foreach($tags as $element) {
|
||||
|
||||
$element = $element->find('a', 0);
|
||||
|
||||
$item = array();
|
||||
$item['uri'] = $element->href;
|
||||
$title = html_entity_decode($element->getAttribute('title'));
|
||||
$content_image = $element->find('div.item_image', 0)->find('.lazyload', 0);
|
||||
|
||||
if($content_image !== NULL) {
|
||||
$content = '<img src="' . $content_image->getAttribute('data-imgsrc') . '" alt="thumbnail">';
|
||||
} else {
|
||||
$content = "";
|
||||
}
|
||||
$date = $element->find('aside.item_absolute', 0)->find('p.item_sup', 0);
|
||||
|
||||
$detailsList = $element->find('section.item_infos', 0);
|
||||
|
||||
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;
|
||||
|
||||
$item['title'] = $title;
|
||||
$item['content'] = $content . $date;
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
}
|
42
bridges/LeMondeInformatiqueBridge.php
Normal file
42
bridges/LeMondeInformatiqueBridge.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
class LeMondeInformatiqueBridge extends FeedExpander {
|
||||
|
||||
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.";
|
||||
|
||||
public function collectData(){
|
||||
$this->collectExpandableDatas(self::URI . 'rss/rss.xml', 10);
|
||||
}
|
||||
|
||||
protected function parseItem($newsItem){
|
||||
$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['title'] = $article_html->find('h1.cleanprint-title', 0)->plaintext;
|
||||
return $item;
|
||||
}
|
||||
|
||||
function StripCDATA($string) {
|
||||
$string = str_replace('<![CDATA[', '', $string);
|
||||
$string = str_replace(']]>', '', $string);
|
||||
return $string;
|
||||
}
|
||||
|
||||
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 $article_html;
|
||||
}
|
||||
}
|
70
bridges/LegifranceJOBridge.php
Normal file
70
bridges/LegifranceJOBridge.php
Normal file
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
class LegifranceJOBridge extends BridgeAbstract{
|
||||
|
||||
const MAINTAINER = 'Pierre Mazière';
|
||||
const NAME = 'Journal Officiel de la République Française';
|
||||
const URI = 'https://www.legifrance.gouv.fr/affichJO.do';
|
||||
const DESCRIPTION = 'Returns the laws and decrees officially registered daily in France';
|
||||
|
||||
const PARAMETERS=array();
|
||||
|
||||
private $author;
|
||||
private $timestamp;
|
||||
private $uri;
|
||||
|
||||
private function extractItem($section,$subsection=null,$origin=null){
|
||||
$item=array();
|
||||
$item['author']=$this->author;
|
||||
$item['timestamp']=$this->timestamp;
|
||||
$item['uri']=$this->uri.'#'.count($this->items);
|
||||
$item['title']=$section->plaintext;
|
||||
|
||||
if(!is_null($origin)){
|
||||
$item['title']='[ '.$item['title'].' / '.$subsection->plaintext.' ] '.$origin->plaintext;
|
||||
$data=$origin;
|
||||
}elseif(!is_null($subsection)){
|
||||
$item['title']='[ '.$item['title'].' ] '.$subsection->plaintext;
|
||||
$data=$subsection;
|
||||
}else{
|
||||
$data=$section;
|
||||
}
|
||||
|
||||
$item['content']='';
|
||||
foreach($data->nextSibling()->find('a') as $content){
|
||||
$text=$content->plaintext;
|
||||
$href=$content->nextSibling()->getAttribute('resource');
|
||||
$item['content'].='<p><a href="'.$href.'">'.$text.'</a></p>';
|
||||
}
|
||||
return $item;
|
||||
}
|
||||
|
||||
public function collectData(){
|
||||
$html=getSimpleHTMLDOM(self::URI)
|
||||
or $this->returnServer('Unable to download '.self::URI);
|
||||
|
||||
$this->author=trim($html->find('h2.title',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/')));
|
||||
|
||||
foreach($html->find('h3') as $section){
|
||||
$subsections=$section->nextSibling()->find('h4');
|
||||
foreach($subsections as $subsection){
|
||||
$origins=$subsection->nextSibling()->find('h5');
|
||||
foreach($origins as $origin){
|
||||
$this->items[]=$this->extractItem($section,$subsection,$origin);
|
||||
}
|
||||
if(!empty($origins)){
|
||||
continue;
|
||||
}
|
||||
$this->items[]=$this->extractItem($section,$subsection);
|
||||
}
|
||||
if(!empty($subsections)){
|
||||
continue;
|
||||
}
|
||||
$this->items[]=$this->extractItem($section);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
47
bridges/LesJoiesDuCodeBridge.php
Normal file
47
bridges/LesJoiesDuCodeBridge.php
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
class LesJoiesDuCodeBridge extends BridgeAbstract{
|
||||
|
||||
const MAINTAINER = "superbaillot.net";
|
||||
const NAME = "Les Joies Du Code";
|
||||
const URI = "http://lesjoiesducode.fr/";
|
||||
const CACHE_TIMEOUT = 7200; // 2h
|
||||
const DESCRIPTION = "LesJoiesDuCode";
|
||||
|
||||
public function collectData(){
|
||||
$html = getSimpleHTMLDOM(self::URI)
|
||||
or returnServerError('Could not request LesJoiesDuCode.');
|
||||
|
||||
foreach($html->find('div.blog-post') as $element) {
|
||||
$item = array();
|
||||
$temp = $element->find('h1 a', 0);
|
||||
$titre = html_entity_decode($temp->innertext);
|
||||
$url = $temp->href;
|
||||
|
||||
$temp = $element->find('div.blog-post-content', 0);
|
||||
|
||||
// retrieve .gif instead of static .jpg
|
||||
$images = $temp->find('p img');
|
||||
foreach($images as $image){
|
||||
$img_src = str_replace(".jpg",".gif",$image->src);
|
||||
$image->src = $img_src;
|
||||
}
|
||||
$content = $temp->innertext;
|
||||
|
||||
$auteur = $temp->find('i', 0);
|
||||
$pos = strpos($auteur->innertext, "by");
|
||||
|
||||
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);
|
||||
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
}
|
31
bridges/LichessBridge.php
Normal file
31
bridges/LichessBridge.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
class LichessBridge extends FeedExpander {
|
||||
|
||||
const MAINTAINER = 'AmauryCarrade';
|
||||
const NAME = 'Lichess Blog';
|
||||
const URI = 'http://fr.lichess.org/blog';
|
||||
const DESCRIPTION = 'Returns the 5 newest posts from the Lichess blog (full text)';
|
||||
|
||||
public function collectData(){
|
||||
$this->collectExpandableDatas(self::URI . '.atom', 5);
|
||||
}
|
||||
|
||||
protected function parseItem($newsItem){
|
||||
$item = parent::parseItem($newsItem);
|
||||
$item['content'] = $this->retrieve_lichess_post($item['uri']);
|
||||
return $item;
|
||||
}
|
||||
|
||||
private function retrieve_lichess_post($blog_post_uri){
|
||||
$blog_post_html = getSimpleHTMLDOMCached($blog_post_uri);
|
||||
$blog_post_div = $blog_post_html->find('#lichess_blog', 0);
|
||||
|
||||
$post_chapo = $blog_post_div->find('.shortlede', 0)->innertext;
|
||||
$post_content = $blog_post_div->find('.body', 0)->innertext;
|
||||
|
||||
$content = '<p><em>' . $post_chapo . '</em></p>';
|
||||
$content .= '<div>' . $post_content . '</div>';
|
||||
|
||||
return $content;
|
||||
}
|
||||
}
|
36
bridges/LinkedInCompanyBridge.php
Normal file
36
bridges/LinkedInCompanyBridge.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
class LinkedInCompanyBridge extends BridgeAbstract{
|
||||
|
||||
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 PARAMETERS = array( array(
|
||||
'c'=>array(
|
||||
'name'=>'Company name',
|
||||
'required'=>true
|
||||
)
|
||||
));
|
||||
|
||||
public function collectData(){
|
||||
$html = '';
|
||||
$link = self::URI.'company/'.$this->getInput('c');
|
||||
|
||||
$html = getSimpleHTMLDOM($link)
|
||||
or returnServerError('Could not request LinkedIn.');
|
||||
|
||||
foreach($html->find('//*[@id="my-feed-post"]/li') as $element) {
|
||||
$title = $element->find('span.share-body', 0)->innertext;
|
||||
if ($title) {
|
||||
$item = array();
|
||||
$item['uri'] = $link;
|
||||
$item['title'] = mb_substr(strip_tags($element->find('span.share-body', 0)->innertext), 0 ,100);
|
||||
$item['content'] = strip_tags($element->find('span.share-body', 0)->innertext);
|
||||
$this->items[] = $item;
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
11
bridges/LolibooruBridge.php
Normal file
11
bridges/LolibooruBridge.php
Normal file
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
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";
|
||||
|
||||
}
|
251
bridges/MangareaderBridge.php
Normal file
251
bridges/MangareaderBridge.php
Normal file
@@ -0,0 +1,251 @@
|
||||
<?php
|
||||
class MangareaderBridge extends BridgeAbstract {
|
||||
|
||||
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 PARAMETERS = array(
|
||||
'Get latest updates' => array(),
|
||||
'Get popular mangas' => array(
|
||||
'category' => array(
|
||||
'name' => 'Category',
|
||||
'type' => 'list',
|
||||
'required' => true,
|
||||
'values' => array(
|
||||
'All' => 'all',
|
||||
'Action' => 'action',
|
||||
'Adventure' => 'adventure',
|
||||
'Comedy' => 'comedy',
|
||||
'Demons' => 'demons',
|
||||
'Drama' => 'drama',
|
||||
'Ecchi' => 'ecchi',
|
||||
'Fantasy' => 'fantasy',
|
||||
'Gender Bender' => 'gender-bender',
|
||||
'Harem' => 'harem',
|
||||
'Historical' => 'historical',
|
||||
'Horror' => 'horror',
|
||||
'Josei' => 'josei',
|
||||
'Magic' => 'magic',
|
||||
'Martial Arts' => 'martial-arts',
|
||||
'Mature' => 'mature',
|
||||
'Mecha' => 'mecha',
|
||||
'Military' => 'military',
|
||||
'Mystery' => 'mystery',
|
||||
'One Shot' => 'one-shot',
|
||||
'Psychological' => 'psychological',
|
||||
'Romance' => 'romance',
|
||||
'School Life' => 'school-life',
|
||||
'Sci-Fi' => 'sci-fi',
|
||||
'Seinen' => 'seinen',
|
||||
'Shoujo' => 'shoujo',
|
||||
'Shoujoai' => 'shoujoai',
|
||||
'Shounen' => 'shounen',
|
||||
'Shounenai' => 'shounenai',
|
||||
'Slice of Life' => 'slice-of-life',
|
||||
'Smut' => 'smut',
|
||||
'Sports' => 'sports',
|
||||
'Super Power' => 'super-power',
|
||||
'Supernatural' => 'supernatural',
|
||||
'Tragedy' => 'tragedy',
|
||||
'Vampire' => 'vampire',
|
||||
'Yaoi' => 'yaoi',
|
||||
'Yuri' => 'yuri'
|
||||
),
|
||||
'exampleValue' => 'All',
|
||||
'title' => 'Select your category'
|
||||
)
|
||||
),
|
||||
'Get manga updates' => array(
|
||||
'path' => array(
|
||||
'name' => 'Path',
|
||||
'required' => true,
|
||||
'pattern' => '[a-zA-Z0-9-_]*',
|
||||
'exampleValue' => 'bleach, umi-no-kishidan',
|
||||
'title' => 'URL part of desired manga'
|
||||
),
|
||||
'limit' => array(
|
||||
'name' => 'Limit',
|
||||
'type' => 'number',
|
||||
'defaultValue' => 10,
|
||||
'title' => 'Number of items to return [-1 returns all]'
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
private $request = '';
|
||||
|
||||
public function collectData(){
|
||||
// We'll use the DOM parser for this as it makes navigation easier
|
||||
$html = getContents($this->getURI());
|
||||
if(!$html){
|
||||
returnClientError('Could not receive data for ' . $path . '!');
|
||||
}
|
||||
libxml_use_internal_errors(true);
|
||||
$doc = new DomDocument;
|
||||
@$doc->loadHTML($html);
|
||||
libxml_clear_errors();
|
||||
|
||||
// Navigate via XPath
|
||||
$xpath = new DomXPath($doc);
|
||||
|
||||
$this->request = '';
|
||||
switch($this->queriedContext){
|
||||
case 'Get latest updates':
|
||||
$this->request = 'Latest updates';
|
||||
$this->get_latest_updates($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);
|
||||
break;
|
||||
case 'Get manga updates':
|
||||
$limit = $this->getInput('limit');
|
||||
if(empty($limit)){
|
||||
$limit = self::PARAMETERS[$this->queriedContext]['limit']['defaultValue'];
|
||||
}
|
||||
|
||||
$this->request = $xpath->query(".//*[@id='mangaproperties']//*[@class='aname']")
|
||||
->item(0)
|
||||
->nodeValue;
|
||||
|
||||
$this->get_manga_updates($xpath, $limit);
|
||||
break;
|
||||
}
|
||||
|
||||
// Return some dummy-data if no content available
|
||||
if(empty($this->items)){
|
||||
$item = array();
|
||||
$item['content'] = "<p>No updates available</p>";
|
||||
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
private function get_latest_updates($xpath){
|
||||
// Query each item (consists of Manga + chapters)
|
||||
$nodes = $xpath->query("//*[@id='latestchapters']/table//td");
|
||||
|
||||
foreach ($nodes as $node){
|
||||
// Query the manga
|
||||
$manga = $xpath->query("a[@class='chapter']", $node)->item(0);
|
||||
|
||||
// Collect the chapters for each Manga
|
||||
$chapters = $xpath->query("a[@class='chaptersrec']", $node);
|
||||
|
||||
if (isset($manga) && $chapters->length >= 1){
|
||||
$item = array();
|
||||
$item['uri'] = self::URI . htmlspecialchars($manga->getAttribute('href'));
|
||||
$item['title'] = htmlspecialchars($manga->nodeValue);
|
||||
|
||||
// Add each chapter to the feed
|
||||
$item['content'] = "";
|
||||
|
||||
foreach ($chapters as $chapter){
|
||||
if($item['content'] <> ""){
|
||||
$item['content'] .= "<br>";
|
||||
}
|
||||
$item['content'] .=
|
||||
"<a href='"
|
||||
. self::URI
|
||||
. htmlspecialchars($chapter->getAttribute('href'))
|
||||
. "'>"
|
||||
. htmlspecialchars($chapter->nodeValue)
|
||||
. "</a>";
|
||||
}
|
||||
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function get_popular_mangas($xpath){
|
||||
// Query all mangas
|
||||
$mangas = $xpath->query("//*[@id='mangaresults']/*[@class='mangaresultitem']");
|
||||
|
||||
foreach ($mangas as $manga){
|
||||
|
||||
// The thumbnail is encrypted in a css-style...
|
||||
// format: "background-image:url('<the part which is actually interesting>')"
|
||||
$mangaimgelement = $xpath->query(".//*[@class='imgsearchresults']", $manga)
|
||||
->item(0)
|
||||
->getAttribute('style');
|
||||
$thumbnail = substr($mangaimgelement, 22, strlen($mangaimgelement) - 24);
|
||||
|
||||
$item = array();
|
||||
$item['title'] = htmlspecialchars($xpath->query(".//*[@class='manga_name']//a", $manga)
|
||||
->item(0)
|
||||
->nodeValue);
|
||||
$item['uri'] = self::URI . $xpath->query(".//*[@class='manga_name']//a", $manga)
|
||||
->item(0)
|
||||
->getAttribute('href');
|
||||
$item['author'] = htmlspecialchars($xpath->query("//*[@class='author_name']", $manga)
|
||||
->item(0)
|
||||
->nodeValue);
|
||||
$item['chaptercount'] = $xpath->query(".//*[@class='chapter_count']", $manga)
|
||||
->item(0)
|
||||
->nodeValue;
|
||||
$item['genre'] = htmlspecialchars($xpath->query(".//*[@class='manga_genre']", $manga)
|
||||
->item(0)
|
||||
->nodeValue);
|
||||
$item['content'] = <<<EOD
|
||||
<a href="{$item['uri']}"><img src="{$thumbnail}" alt="{$item['title']}" /></a>
|
||||
<p>{$item['genre']}</p>
|
||||
<p>{$item['chaptercount']}</p>
|
||||
EOD;
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
private function get_manga_updates($xpath, $limit){
|
||||
$query = "(.//*[@id='listing']//tr)[position() > 1]";
|
||||
|
||||
if($limit !== -1){
|
||||
$query = "(.//*[@id='listing']//tr)[position() > 1][position() > last() - {$limit}]";
|
||||
}
|
||||
|
||||
$chapters = $xpath->query($query);
|
||||
|
||||
foreach ($chapters as $chapter){
|
||||
$item = array();
|
||||
$item['title'] = htmlspecialchars($xpath->query("td[1]", $chapter)
|
||||
->item(0)
|
||||
->nodeValue);
|
||||
$item['uri'] = self::URI . $xpath->query("td[1]/a", $chapter)
|
||||
->item(0)
|
||||
->getAttribute('href');
|
||||
$item['timestamp'] = strtotime($xpath->query("td[2]", $chapter)
|
||||
->item(0)
|
||||
->nodeValue);
|
||||
array_unshift($this->items, $item);
|
||||
}
|
||||
}
|
||||
|
||||
public function getURI(){
|
||||
switch($this->queriedContext){
|
||||
case 'Get latest updates':
|
||||
$path = "latest";
|
||||
break;
|
||||
case 'Get popular mangas':
|
||||
$path = "popular";
|
||||
if($this->getInput('category') !== "all"){
|
||||
$path .= "/" . $this->getInput('category');
|
||||
}
|
||||
break;
|
||||
case 'Get manga updates':
|
||||
$path = $this->getInput('path');
|
||||
break;
|
||||
}
|
||||
return self::URI . $path;
|
||||
}
|
||||
|
||||
|
||||
public function getName(){
|
||||
return (!empty($this->request) ? $this->request . ' - ' : '') . 'Mangareader Bridge';
|
||||
}
|
||||
}
|
||||
?>
|
11
bridges/MilbooruBridge.php
Normal file
11
bridges/MilbooruBridge.php
Normal file
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
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";
|
||||
|
||||
}
|
46
bridges/MoebooruBridge.php
Normal file
46
bridges/MoebooruBridge.php
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
class MoebooruBridge extends BridgeAbstract{
|
||||
|
||||
const NAME = "Moebooru";
|
||||
const URI = "https://moe.dev.myconan.net/";
|
||||
const CACHE_TIMEOUT = 1800; // 30min
|
||||
const DESCRIPTION = "Returns images from given page";
|
||||
|
||||
const PARAMETERS = array( array(
|
||||
'p'=>array(
|
||||
'name'=>'page',
|
||||
'defaultValue'=>1,
|
||||
'type'=>'number'
|
||||
),
|
||||
't'=>array('name'=>'tags')
|
||||
));
|
||||
|
||||
protected function getFullURI(){
|
||||
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);
|
||||
$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'];
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
}
|
23
bridges/MondeDiploBridge.php
Normal file
23
bridges/MondeDiploBridge.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
class MondeDiploBridge extends BridgeAbstract{
|
||||
|
||||
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.";
|
||||
|
||||
public function collectData(){
|
||||
$html = getSimpleHTMLDOM(self::URI)
|
||||
or returnServerError('Could not request MondeDiplo. for : ' . self::URI);
|
||||
|
||||
foreach($html->find('div.unarticle') as $article) {
|
||||
$element = $article->parent();
|
||||
$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);
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
}
|
33
bridges/MsnMondeBridge.php
Normal file
33
bridges/MsnMondeBridge.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
class MsnMondeBridge extends BridgeAbstract{
|
||||
|
||||
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)";
|
||||
|
||||
public function getURI(){
|
||||
return self::URI.'fr-fr/actualite/monde';
|
||||
}
|
||||
|
||||
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.');
|
||||
$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->items[] = $item;
|
||||
$limit++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
12
bridges/MspabooruBridge.php
Normal file
12
bridges/MspabooruBridge.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
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 PIDBYPAGE=50;
|
||||
}
|
43
bridges/NasaApodBridge.php
Normal file
43
bridges/NasaApodBridge.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
class NasaApodBridge extends BridgeAbstract{
|
||||
|
||||
const MAINTAINER = "corenting";
|
||||
const NAME = "NASA APOD Bridge";
|
||||
const URI = "http://apod.nasa.gov/apod/";
|
||||
const CACHE_TIMEOUT = 43200; // 12h
|
||||
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');
|
||||
$list = explode("<br>", $html->find('b', 0)->innertext);
|
||||
|
||||
for($i = 0; $i < 3;$i++)
|
||||
{
|
||||
$line = $list[$i];
|
||||
$item = array();
|
||||
|
||||
$uri_page = $html->find('a',$i + 3)->href;
|
||||
$uri = self::URI.$uri_page;
|
||||
$item['uri'] = $uri;
|
||||
|
||||
$picture_html = getSimpleHTMLDOM($uri);
|
||||
$picture_html_string = $picture_html->innertext;
|
||||
|
||||
//Extract image and explanation
|
||||
$media = $picture_html->find('p',1)->innertext;
|
||||
$media = strstr($media, '<br>');
|
||||
$media = preg_replace('/<br>/', '', $media, 1);
|
||||
$explanation = $picture_html->find('p',2)->innertext;
|
||||
|
||||
//Extract date from the picture page
|
||||
$date = explode(" ", $picture_html->find('p',1)->innertext);
|
||||
$item['timestamp'] = strtotime($date[4].$date[3].$date[2]);
|
||||
|
||||
//Other informations
|
||||
$item['content'] = $media.'<br />'.$explanation;
|
||||
$item['title'] = $picture_html->find('b',0)->innertext;
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
}
|
55
bridges/NeuviemeArtBridge.php
Normal file
55
bridges/NeuviemeArtBridge.php
Normal file
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
class NeuviemeArtBridge extends FeedExpander {
|
||||
|
||||
const MAINTAINER = "ORelio";
|
||||
const NAME = '9ème Art Bridge';
|
||||
const URI = "http://www.9emeart.fr/";
|
||||
const DESCRIPTION = "Returns the newest articles.";
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
protected function parseItem($item){
|
||||
$item = parent::parseItem($item);
|
||||
|
||||
$article_html = getSimpleHTMLDOMCached($item['uri']);
|
||||
if(!$article_html){
|
||||
$item['content'] = 'Could not request 9eme Art: '.$item['uri'];
|
||||
return $item;
|
||||
}
|
||||
|
||||
$article_image = '';
|
||||
foreach ($article_html->find('img.img_full') as $img){
|
||||
if ($img->alt == $item['title']){
|
||||
$article_image = self::URI.$img->src;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$article_content='';
|
||||
if($article_image){
|
||||
$article_content = '<p><img src="'.$article_image.'" /></p>';
|
||||
}
|
||||
$article_content .= str_replace(
|
||||
'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', '>');
|
||||
|
||||
$item['content'] = $article_content;
|
||||
|
||||
return $item;
|
||||
}
|
||||
|
||||
public function collectData(){
|
||||
$feedUrl = self::URI.'9emeart.rss';
|
||||
$this->collectExpandableDatas($feedUrl);
|
||||
}
|
||||
}
|
29
bridges/NextInpactBridge.php
Normal file
29
bridges/NextInpactBridge.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
class NextInpactBridge extends FeedExpander {
|
||||
|
||||
const MAINTAINER = "qwertygc";
|
||||
const NAME = "NextInpact Bridge";
|
||||
const URI = "http://www.nextinpact.com/";
|
||||
const DESCRIPTION = "Returns the newest articles.";
|
||||
|
||||
public function collectData(){
|
||||
$this->collectExpandableDatas(self::URI . 'rss/news.xml', 10);
|
||||
}
|
||||
|
||||
protected function parseItem($newsItem){
|
||||
$item = parent::parseItem($newsItem);
|
||||
$item['content'] = $this->ExtractContent($item['uri']);
|
||||
return $item;
|
||||
}
|
||||
|
||||
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>';
|
||||
$premium_article = $html2->find('h2.title_reserve_article', 0);
|
||||
if (is_object($premium_article))
|
||||
$text = $text.'<p><em>'.$premium_article->innertext.'</em></p>';
|
||||
return $text;
|
||||
}
|
||||
}
|
70
bridges/NextgovBridge.php
Normal file
70
bridges/NextgovBridge.php
Normal file
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
class NextgovBridge extends FeedExpander {
|
||||
|
||||
const MAINTAINER = 'ORelio';
|
||||
const NAME = 'Nextgov Bridge';
|
||||
const URI = 'https://www.nextgov.com/';
|
||||
const DESCRIPTION = 'USA Federal technology news, best practices, and web 2.0 tools.';
|
||||
|
||||
const PARAMETERS = array( array(
|
||||
'category'=>array(
|
||||
'name'=>'Category',
|
||||
'type'=>'list',
|
||||
'values'=>array(
|
||||
'All'=>'all',
|
||||
'Technology News'=>'technology-news',
|
||||
'CIO Briefing'=>'cio-briefing',
|
||||
'Emerging Tech'=>'emerging-tech',
|
||||
'Cloud'=>'cloud-computing',
|
||||
'Cybersecurity'=>'cybersecurity',
|
||||
'Mobile'=>'mobile',
|
||||
'Health'=>'health',
|
||||
'Defense'=>'defense',
|
||||
'Big Data'=>'big-data'
|
||||
)
|
||||
)
|
||||
));
|
||||
|
||||
public function collectData(){
|
||||
$this->collectExpandableDatas(self::URI . 'rss/' . $this->getInput('category') . '/', 10);
|
||||
}
|
||||
|
||||
protected function parseItem($newsItem){
|
||||
$item = parent::parseItem($newsItem);
|
||||
|
||||
$item['content'] = '';
|
||||
|
||||
$namespaces = $newsItem->getNamespaces(true);
|
||||
if(isset($namespaces['media'])){
|
||||
$media = $newsItem->children($namespaces['media']);
|
||||
if(isset($media->content)){
|
||||
$attributes = $media->content->attributes();
|
||||
$item['content'] = '<img src="' . $attributes['url'] . '">';
|
||||
}
|
||||
}
|
||||
|
||||
$item['content'] .= $this->ExtractContent($item['uri']);
|
||||
return $item;
|
||||
}
|
||||
|
||||
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){
|
||||
$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 = ($article_thumbnail == '' ? '' : '<p><img src="'.$article_thumbnail.'" /></p>')
|
||||
.'<p><b>'.$article_subtitle.'</b></p>'
|
||||
.trim($contents);
|
||||
}
|
||||
}
|
32
bridges/NiceMatinBridge.php
Normal file
32
bridges/NiceMatinBridge.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?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)";
|
||||
|
||||
public function collectData(){
|
||||
$this->collectExpandableDatas(self::URI . 'derniere-minute/rss', 10);
|
||||
}
|
||||
|
||||
protected function parseItem($newsItem){
|
||||
$item = parent::parseItem($newsItem);
|
||||
$item['content'] = $this->NiceMatinExtractContent($item['uri']);
|
||||
return $item;
|
||||
}
|
||||
|
||||
private function NiceMatinExtractContent($url) {
|
||||
$html = getSimpleHTMLDOMCached($url);
|
||||
if(!$html)
|
||||
return 'Could not acquire content from url: ' . $url . '!';
|
||||
|
||||
$content = $html->find('article', 0);
|
||||
if(!$content)
|
||||
return 'Could not find \'section\'!';
|
||||
|
||||
$text = preg_replace('#<script(.*?)>(.*?)</script>#is', '', $content->innertext);
|
||||
$text = strip_tags($text, '<p><a><img>');
|
||||
return $text;
|
||||
}
|
||||
}
|
52
bridges/NovelUpdatesBridge.php
Normal file
52
bridges/NovelUpdatesBridge.php
Normal file
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
class NovelUpdatesBridge extends BridgeAbstract{
|
||||
|
||||
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 PARAMETERS = array( array(
|
||||
'n'=>array(
|
||||
'name'=>'Novel name as found in the url',
|
||||
'exampleValue'=>'spirit-realm',
|
||||
'required'=>true
|
||||
)
|
||||
));
|
||||
|
||||
private $seriesTitle='';
|
||||
|
||||
public function getURI(){
|
||||
return static::URI.'/series/'.$this->getInput('n').'/';
|
||||
}
|
||||
|
||||
public function collectData(){
|
||||
$fullhtml = getSimpleHTMLDOM($this->getURI())
|
||||
or returnServerError('Could not request NovelUpdates, novel "'.$this->getInput('n').'" not found');
|
||||
|
||||
$this->seriesTitle = $fullhtml->find('h4.seriestitle', 0)->plaintext;
|
||||
// dirty fix for nasty simpledom bug: https://github.com/sebsauvage/rss-bridge/issues/259
|
||||
// forcefully removes tbody
|
||||
$html = $fullhtml->find('table#myTable', 0)->innertext;
|
||||
$html = stristr($html, '<tbody>'); //strip thead
|
||||
$html = stristr($html, '<tr>'); //remove tbody
|
||||
$html = str_get_html(stristr($html, '</tbody>', true)); //remove last tbody and get back as an array
|
||||
foreach($html->find('tr') as $element){
|
||||
$item = array();
|
||||
$item['uri'] = $element->find('td', 2)->find('a', 0)->href;
|
||||
$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>';
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return $this->seriesTitle. ' - ' . static::NAME;
|
||||
}
|
||||
}
|
46
bridges/OpenClassroomsBridge.php
Normal file
46
bridges/OpenClassroomsBridge.php
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
class OpenClassroomsBridge extends BridgeAbstract{
|
||||
|
||||
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 PARAMETERS = array( array(
|
||||
'u'=>array(
|
||||
'name'=>'Catégorie',
|
||||
'type'=>'list',
|
||||
'required'=>true,
|
||||
'values'=>array(
|
||||
'Arts & Culture'=>'arts',
|
||||
'Code'=>'code',
|
||||
'Design'=>'design',
|
||||
'Entreprise'=>'business',
|
||||
'Numérique'=>'digital',
|
||||
'Sciences'=>'sciences',
|
||||
'Sciences Humaines'=>'humainities',
|
||||
'Systèmes d\'information'=>'it',
|
||||
'Autres'=>'others'
|
||||
)
|
||||
)
|
||||
));
|
||||
|
||||
public function getURI(){
|
||||
return self::URI.'/courses?categories='.$this->getInput('u').'&'
|
||||
.'title=&sort=updatedAt+desc';
|
||||
}
|
||||
|
||||
public function collectData(){
|
||||
$html = getSimpleHTMLDOM($this->getURI())
|
||||
or returnServerError('Could not request OpenClassrooms.');
|
||||
|
||||
foreach($html->find('.courseListItem') as $element) {
|
||||
$item = array();
|
||||
$item['uri'] = self::URI.$element->find('a', 0)->href;
|
||||
$item['title'] = $element->find('h3', 0)->plaintext;
|
||||
$item['content'] = $element->find('slidingItem__descriptionContent', 0)->plaintext;
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
}
|
96
bridges/ParuVenduImmoBridge.php
Normal file
96
bridges/ParuVenduImmoBridge.php
Normal file
@@ -0,0 +1,96 @@
|
||||
<?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.";
|
||||
|
||||
|
||||
const PARAMETERS = array( array(
|
||||
'minarea'=>array(
|
||||
'name'=>'Minimal surface m²',
|
||||
'type'=>'number'
|
||||
),
|
||||
'maxprice'=>array(
|
||||
'name'=>'Max price',
|
||||
'type'=>'number'
|
||||
),
|
||||
'pa'=>array(
|
||||
'name'=>'Country code',
|
||||
'exampleValue'=>'FR'
|
||||
),
|
||||
'lo'=>array('name'=>'department numbers or postal codes, comma-separated')
|
||||
));
|
||||
|
||||
public function collectData()
|
||||
{
|
||||
$html = getSimpleHTMLDOM($this->getURI())
|
||||
or returnServerError('Could not request paruvendu.');
|
||||
|
||||
foreach($html->find('div.annonce a') as $element) {
|
||||
|
||||
if (!$element->title) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$img ='';
|
||||
foreach($element->find('span.img img') as $img) {
|
||||
if ($img->original) {
|
||||
$img = '<img src="'.$img->original.'" />';
|
||||
}
|
||||
}
|
||||
|
||||
$desc = $element->find('span.desc')[0]->innertext;
|
||||
$desc = str_replace("voir l'annonce", '', $desc);
|
||||
|
||||
$price = $element->find('span.price')[0]->innertext;
|
||||
|
||||
list($href) = explode('#', $element->href);
|
||||
|
||||
$item = array();
|
||||
$item['uri'] = self::URI.$href;
|
||||
$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;
|
||||
|
||||
if ($this->getInput('minarea')) {
|
||||
$link .= '&sur0='.urlencode($this->getInput('minarea'));
|
||||
}
|
||||
|
||||
if ($this->getInput('maxprice')) {
|
||||
$link .= '&px1='.urlencode($this->getInput('maxprice'));
|
||||
}
|
||||
|
||||
if ($this->getInput('pa')) {
|
||||
$link .= '&pa='.urlencode($this->getInput('pa'));
|
||||
}
|
||||
|
||||
if ($this->getInput('lo')) {
|
||||
$link .= '&lo='.urlencode($this->getInput('lo'));
|
||||
}
|
||||
return $link;
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
$request='';
|
||||
$minarea=$this->getInput('minarea');
|
||||
if(!empty($minarea)){
|
||||
$request .= ' '.$minarea.' m2';
|
||||
}
|
||||
$location=$this->getInput('lo');
|
||||
if(!empty($location)){
|
||||
$request .= ' In: '.$location;
|
||||
}
|
||||
return 'Paru Vendu Immobilier'.$request;
|
||||
}
|
||||
}
|
73
bridges/PickyWallpapersBridge.php
Normal file
73
bridges/PickyWallpapersBridge.php
Normal file
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
class PickyWallpapersBridge extends BridgeAbstract {
|
||||
|
||||
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 PARAMETERS = array( array(
|
||||
'c'=>array(
|
||||
'name'=>'category',
|
||||
'required'=>true
|
||||
),
|
||||
's'=>array('name'=>'subcategory'),
|
||||
'm'=>array(
|
||||
'name'=>'Max number of wallpapers',
|
||||
'defaultValue'=>12,
|
||||
'type'=>'number'
|
||||
),
|
||||
'r'=>array(
|
||||
'name'=>'resolution',
|
||||
'exampleValue'=>'1920x1200, 1680x1050,…',
|
||||
'defaultValue'=>'1920x1200',
|
||||
'pattern'=>'[0-9]{3,4}x[0-9]{3,4}'
|
||||
)
|
||||
));
|
||||
|
||||
|
||||
public function collectData(){
|
||||
$lastpage = 1;
|
||||
$num = 0;
|
||||
$max = $this->getInput('m');
|
||||
$resolution = $this->getInput('r'); // Wide wallpaper default
|
||||
|
||||
for ($page = 1; $page <= $lastpage; $page++) {
|
||||
$html = getSimpleHTMLDOM($this->getURI().'/page-'.$page.'/')
|
||||
or returnServerError('No results for this query.');
|
||||
|
||||
if ($page === 1) {
|
||||
preg_match('/page-(\d+)\/$/', $html->find('.pages li a', -2)->href, $matches);
|
||||
$lastpage = min($matches[1], ceil($max/12));
|
||||
}
|
||||
|
||||
foreach($html->find('.items li img') as $element) {
|
||||
|
||||
$item = array();
|
||||
$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>';
|
||||
$this->items[] = $item;
|
||||
|
||||
$num++;
|
||||
if ($num >= $max)
|
||||
break 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getURI(){
|
||||
$subcategory = $this->getInput('s');
|
||||
$link = self::URI.$this->getInput('r').'/'.$this->getInput('c').'/'.$subcategory;
|
||||
return $link;
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
$subcategory = $this->getInput('s');
|
||||
return 'PickyWallpapers - '.$this->getInput('c')
|
||||
.($subcategory? ' > '.$subcategory : '')
|
||||
.' ['.$this->getInput('r').']';
|
||||
}
|
||||
}
|
121
bridges/PinterestBridge.php
Normal file
121
bridges/PinterestBridge.php
Normal file
@@ -0,0 +1,121 @@
|
||||
<?php
|
||||
class PinterestBridge extends BridgeAbstract {
|
||||
|
||||
const MAINTAINER = "pauder";
|
||||
const NAME = "Pinterest Bridge";
|
||||
const URI = "http://www.pinterest.com/";
|
||||
const DESCRIPTION = "Returns the newest images on a board";
|
||||
|
||||
const PARAMETERS = array(
|
||||
'By username and board' => array(
|
||||
'u' => array(
|
||||
'name' => 'username',
|
||||
'required' => true
|
||||
),
|
||||
'b' => array(
|
||||
'name' => 'board',
|
||||
'required' => true
|
||||
)
|
||||
),
|
||||
'From search' => array(
|
||||
'q' => array(
|
||||
'name' => 'Keyword',
|
||||
'required' => true
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
public function collectData(){
|
||||
$html = getSimpleHTMLDOM($this->getURI());
|
||||
if(!$html){
|
||||
switch($this->queriedContext){
|
||||
case 'By username and board':
|
||||
returnServerError('Username and/or board not found');
|
||||
case 'From search':
|
||||
returnServerError('Could not request Pinterest.');
|
||||
}
|
||||
}
|
||||
|
||||
if($this->queriedContext === 'From search'){
|
||||
foreach($html->find('div.pinWrapper') as $div){
|
||||
$item = array();
|
||||
|
||||
$a = $div->find('a.pinImageWrapper', 0);
|
||||
$img = $a->find('img', 0);
|
||||
|
||||
$item['uri'] = $this->getURI() . $a->getAttribute('href');
|
||||
$item['content'] = '<img src="'
|
||||
. htmlentities(str_replace('/236x/', '/736x/', $img->getAttribute('src')))
|
||||
. '" alt="" />';
|
||||
|
||||
$avatar = $div->find('div.creditImg', 0)->find('img', 0);
|
||||
$avatar = $avatar->getAttribute('data-src');
|
||||
$avatar = str_replace("\\", "", $avatar);
|
||||
|
||||
$username = $div->find('div.creditName', 0);
|
||||
$board = $div->find('div.creditTitle', 0);
|
||||
|
||||
$item['username'] = $username->innertext;
|
||||
$item['fullname'] = $board->innertext;
|
||||
$item['avatar'] = $avatar;
|
||||
|
||||
$item['content'] .= '<br /><img align="left" style="margin: 2px 4px;" src="'
|
||||
. htmlentities($item['avatar'])
|
||||
. '" /> <strong>'
|
||||
. $item['username']
|
||||
. '</strong>'
|
||||
. '<br />'
|
||||
. $item['fullname'];
|
||||
|
||||
$item['title'] = $img->getAttribute('alt');
|
||||
$this->items[] = $item;
|
||||
}
|
||||
} elseif($this->queriedContext === 'By username and board'){
|
||||
$container = $html->find('SCRIPT[type="application/ld+json"]', 0)
|
||||
or returnServerError('Unable to find data container!');
|
||||
|
||||
$json = json_decode($container->innertext, true);
|
||||
|
||||
foreach($json['itemListElement'] as $element){
|
||||
$item = array();
|
||||
|
||||
$item['uri'] = $element['item']['sharedContent']['author']['url'];
|
||||
$item['title'] = $element['item']['name'];
|
||||
$item['author'] = $element['item']['user']['name'];
|
||||
$item['timestamp'] = strtotime($element['item']['datePublished']);
|
||||
$item['content'] = <<<EOD
|
||||
<a href="{$item['uri']}">
|
||||
<img src="{$element['item']['image']}">
|
||||
</a>
|
||||
<p>{$element['item']['text']}</p>
|
||||
EOD;
|
||||
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getURI(){
|
||||
switch($this->queriedContext){
|
||||
case 'By username and board':
|
||||
$uri = self::URI . urlencode($this->getInput('u')) . '/' . urlencode($this->getInput('b'));
|
||||
break;
|
||||
case 'From search':
|
||||
$uri = self::URI . 'search/?q=' . urlencode($this->getInput('q'));
|
||||
break;
|
||||
}
|
||||
return $uri;
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
switch($this->queriedContext){
|
||||
case 'By username and board':
|
||||
$specific = $this->getInput('u') . '-' . $this->getInput('b');
|
||||
break;
|
||||
case 'From search':
|
||||
$specific = $this->getInput('q');
|
||||
break;
|
||||
}
|
||||
return $specific . ' - ' . self::NAME;
|
||||
}
|
||||
}
|
31
bridges/PlanetLibreBridge.php
Normal file
31
bridges/PlanetLibreBridge.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
class PlanetLibreBridge extends BridgeAbstract{
|
||||
|
||||
const MAINTAINER = "pit-fgfjiudghdf";
|
||||
const NAME = "PlanetLibre";
|
||||
const URI = "http://www.planet-libre.org";
|
||||
const DESCRIPTION = "Returns the 5 newest posts from PlanetLibre (full text)";
|
||||
|
||||
private function PlanetLibreExtractContent($url){
|
||||
$html2 = getSimpleHTMLDOM($url);
|
||||
$text = $html2->find('div[class="post-text"]', 0)->innertext;
|
||||
return $text;
|
||||
}
|
||||
|
||||
public function collectData(){
|
||||
$html = getSimpleHTMLDOM(self::URI)
|
||||
or returnServerError('Could not request PlanetLibre.');
|
||||
$limit = 0;
|
||||
foreach($html->find('div.post') as $element) {
|
||||
if($limit < 5) {
|
||||
$item = array();
|
||||
$item['title'] = $element->find('h1', 0)->plaintext;
|
||||
$item['uri'] = $element->find('a', 0)->href;
|
||||
$item['timestamp'] = strtotime(str_replace('/', '-', $element->find('div[class="post-date"]', 0)->plaintext));
|
||||
$item['content'] = $this->PlanetLibreExtractContent($item['uri']);
|
||||
$this->items[] = $item;
|
||||
$limit++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
50
bridges/RTBFBridge.php
Normal file
50
bridges/RTBFBridge.php
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
class RTBFBridge extends BridgeAbstract {
|
||||
const NAME = "RTBF Bridge";
|
||||
const URI = "http://www.rtbf.be/auvio/emissions/";
|
||||
const CACHE_TIMEOUT = 21600; //6h
|
||||
const DESCRIPTION = "Returns the newest RTBF videos by series ID";
|
||||
const MAINTAINER = "Frenzie";
|
||||
|
||||
const PARAMETERS = array( array(
|
||||
'c'=>array(
|
||||
'name'=>'series id',
|
||||
'exampleValue'=>9500,
|
||||
'required'=>true
|
||||
)
|
||||
));
|
||||
|
||||
public function collectData(){
|
||||
$html = '';
|
||||
$limit = 10;
|
||||
$count = 0;
|
||||
|
||||
$html = getSimpleHTMLDOM($this->getURI())
|
||||
or returnServerError('Could not request RTBF.');
|
||||
|
||||
foreach($html->find('section[id!=widget-ml-avoiraussi-] .rtbf-media-grid article') as $element) {
|
||||
if($count >= $limit) {
|
||||
break;
|
||||
}
|
||||
$item = array();
|
||||
$item['id'] = $element->getAttribute('data-id');
|
||||
$item['uri'] = self::URI.'detail?id='.$item['id'];
|
||||
$thumbnailUriSrcSet = explode(',', $element->find('figure .www-img-16by9 img', 0)->getAttribute('data-srcset'));
|
||||
$thumbnailUriLastSrc = end($thumbnailUriSrcSet);
|
||||
$thumbnailUri = explode(' ', $thumbnailUriLastSrc)[0];
|
||||
$item['title'] = trim($element->find('h3',0)->plaintext) . ' - ' . trim($element->find('h4',0)->plaintext);
|
||||
$item['timestamp'] = strtotime($element->find('time', 0)->getAttribute('datetime'));
|
||||
$item['content'] = '<a href="' . $item['uri'] . '"><img src="' . $thumbnailUri . '" /></a>';
|
||||
$this->items[] = $item;
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
|
||||
public function getURI(){
|
||||
return self::URI.'detail?id='.$this->getInput('c');
|
||||
}
|
||||
|
||||
public function getName(){
|
||||
return $this->getInput('c') .' - RTBF Bridge';
|
||||
}
|
||||
}
|
43
bridges/ReadComicsBridge.php
Normal file
43
bridges/ReadComicsBridge.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
class ReadComicsBridge extends BridgeAbstract{
|
||||
|
||||
const MAINTAINER = "niawag";
|
||||
const NAME = "Read Comics";
|
||||
const URI = "http://www.readcomics.tv/";
|
||||
const DESCRIPTION = "Enter the comics as they appear in the website uri, separated by semicolons, ex: good-comic-1;good-comic-2; ...";
|
||||
|
||||
const PARAMETERS = array( array(
|
||||
'q'=>array(
|
||||
'name'=>'keywords, separated by semicolons',
|
||||
'exampleValue'=>'first list;second list;...',
|
||||
'required'=>true
|
||||
),
|
||||
));
|
||||
|
||||
public function collectData(){
|
||||
|
||||
function parseDateTimestamp($element){
|
||||
$guessedDate = $element->find('span',0)->plaintext;
|
||||
$guessedDate = strptime($guessedDate, '%m/%d/%Y');
|
||||
$timestamp = mktime(0, 0, 0, $guessedDate['tm_mon'] + 1, $guessedDate['tm_mday'], date('Y'));
|
||||
|
||||
return $timestamp;
|
||||
}
|
||||
|
||||
$keywordsList = explode(";",$this->getInput('q'));
|
||||
foreach($keywordsList as $keywords){
|
||||
$html = $this->getSimpleHTMLDOM(self::URI.'comic/'.rawurlencode($keywords))
|
||||
or $this->returnServerError('Could not request readcomics.tv.');
|
||||
|
||||
foreach($html->find('li') as $element) {
|
||||
$item = array();
|
||||
$item['uri'] = $element->find('a.ch-name',0)->href;
|
||||
$item['id'] = $item['uri'];
|
||||
$item['timestamp'] = parseDateTimestamp($element);
|
||||
$item['title'] = $element->find('a.ch-name',0)->plaintext;
|
||||
if(isset($item['title']))
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
120
bridges/Releases3DSBridge.php
Normal file
120
bridges/Releases3DSBridge.php
Normal file
@@ -0,0 +1,120 @@
|
||||
<?php
|
||||
class Releases3DSBridge extends BridgeAbstract {
|
||||
|
||||
const MAINTAINER = "ORelio";
|
||||
const NAME = "3DS Scene Releases";
|
||||
const URI = "http://www.3dsdb.com/";
|
||||
const CACHE_TIMEOUT = 10800; // 3h
|
||||
const DESCRIPTION = "Returns the newest scene releases.";
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
function TypeToString($type) {
|
||||
switch ($type) {
|
||||
case 1: return '3DS Game';
|
||||
case 4: return 'eShop';
|
||||
default: return '??? ('.$type.')';
|
||||
}
|
||||
}
|
||||
|
||||
function CardToString($card) {
|
||||
switch ($card) {
|
||||
case 1: return 'Regular (CARD1)';
|
||||
case 2: return 'NAND (CARD2)';
|
||||
default: return '??? ('.$card.')';
|
||||
}
|
||||
}
|
||||
|
||||
$dataUrl = self::URI.'xml.php';
|
||||
$xml = getContents($dataUrl) or returnServerError('Could not request 3dsdb: '.$dataUrl);
|
||||
$limit = 0;
|
||||
|
||||
foreach (array_reverse(explode('<release>', $xml)) as $element) {
|
||||
if ($limit >= 5) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (strpos($element, '</release>') === false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$releasename = ExtractFromDelimiters($element, '<releasename>', '</releasename>');
|
||||
if (empty($releasename)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$id = ExtractFromDelimiters($element, '<id>', '</id>');
|
||||
$name = ExtractFromDelimiters($element, '<name>', '</name>');
|
||||
$publisher = ExtractFromDelimiters($element, '<publisher>', '</publisher>');
|
||||
$region = ExtractFromDelimiters($element, '<region>', '</region>');
|
||||
$group = ExtractFromDelimiters($element, '<group>', '</group>');
|
||||
$imagesize = ExtractFromDelimiters($element, '<imagesize>', '</imagesize>');
|
||||
$serial = ExtractFromDelimiters($element, '<serial>', '</serial>');
|
||||
$titleid = ExtractFromDelimiters($element, '<titleid>', '</titleid>');
|
||||
$imgcrc = ExtractFromDelimiters($element, '<imgcrc>', '</imgcrc>');
|
||||
$filename = ExtractFromDelimiters($element, '<filename>', '</filename>');
|
||||
$trimmedsize = ExtractFromDelimiters($element, '<trimmedsize>', '</trimmedsize>');
|
||||
$firmware = ExtractFromDelimiters($element, '<firmware>', '</firmware>');
|
||||
$type = ExtractFromDelimiters($element, '<type>', '</type>');
|
||||
$card = ExtractFromDelimiters($element, '<card>', '</card>');
|
||||
|
||||
//Retrieve cover art and short desc from IGN?
|
||||
$ignResult = false; $ignDescription = ''; $ignLink = ''; $ignDate = time(); $ignCoverArt = '';
|
||||
$ignSearchUrl = 'http://www.ign.com/search?q='.urlencode($name);
|
||||
if ($ignResult = getSimpleHTMLDOM($ignSearchUrl)) {
|
||||
$ignCoverArt = $ignResult->find('div.search-item-media', 0)->find('img', 0)->src;
|
||||
$ignDesc = $ignResult->find('div.search-item-description', 0)->plaintext;
|
||||
$ignLink = $ignResult->find('div.search-item-sub-title', 0)->find('a', 1)->href;
|
||||
$ignDate = strtotime(trim($ignResult->find('span.publish-date', 0)->plaintext));
|
||||
$ignDescription = '<div><img src="'.$ignCoverArt.'" /></div><div>'.$ignDesc.' <a href="'.$ignLink.'">More at IGN</a></div>';
|
||||
}
|
||||
|
||||
//Main section : Release description from 3DS database
|
||||
$releaseDescription = '<h3>Release Details</h3>'
|
||||
.'<b>Release ID: </b>'.$id.'<br />'
|
||||
.'<b>Game Name: </b>'.$name.'<br />'
|
||||
.'<b>Publisher: </b>'.$publisher.'<br />'
|
||||
.'<b>Region: </b>'.$region.'<br />'
|
||||
.'<b>Group: </b>'.$group.'<br />'
|
||||
.'<b>Image size: </b>'.(intval($imagesize)/8).'MB<br />'
|
||||
.'<b>Serial: </b>'.$serial.'<br />'
|
||||
.'<b>Title ID: </b>'.$titleid.'<br />'
|
||||
.'<b>Image CRC: </b>'.$imgcrc.'<br />'
|
||||
.'<b>File Name: </b>'.$filename.'<br />'
|
||||
.'<b>Release Name: </b>'.$releasename.'<br />'
|
||||
.'<b>Trimmed size: </b>'.intval(intval($trimmedsize)/1048576).'MB<br />'
|
||||
.'<b>Firmware: </b>'.$firmware.'<br />'
|
||||
.'<b>Type: </b>'.TypeToString($type).'<br />'
|
||||
.'<b>Card: </b>'.CardToString($card).'<br />';
|
||||
|
||||
//Build search links section to facilitate release search using search engines
|
||||
$releaseNameEncoded = urlencode(str_replace(' ', '+', $releasename));
|
||||
$searchLinkGoogle = 'https://google.com/?q='.$releaseNameEncoded;
|
||||
$searchLinkDuckDuckGo = 'https://duckduckgo.com/?q='.$releaseNameEncoded;
|
||||
$searchLinkQwant = 'https://lite.qwant.com/?q='.$releaseNameEncoded.'&t=web';
|
||||
$releaseSearchLinks = '<h3>Search this release</h3><ul>'
|
||||
.'<li><a href="'.$searchLinkGoogle.'">Search using Google</a></li>'
|
||||
.'<li><a href="'.$searchLinkDuckDuckGo.'">Search using DuckDuckGo</a></li>'
|
||||
.'<li><a href="'.$searchLinkQwant.'">Search using Qwant</a></li>'
|
||||
.'</ul>';
|
||||
|
||||
//Build and add final item with the above three sections
|
||||
$item = array();
|
||||
$item['title'] = $name;
|
||||
$item['author'] = $publisher;
|
||||
$item['timestamp'] = $ignDate;
|
||||
$item['uri'] = empty($ignLink) ? $searchLinkDuckDuckGo : $ignLink;
|
||||
$item['content'] = $ignDescription.$releaseDescription.$releaseSearchLinks;
|
||||
$this->items[] = $item;
|
||||
$limit++;
|
||||
}
|
||||
}
|
||||
}
|
42
bridges/ReporterreBridge.php
Normal file
42
bridges/ReporterreBridge.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
class ReporterreBridge extends BridgeAbstract{
|
||||
|
||||
const MAINTAINER = "nyutag";
|
||||
const NAME = "Reporterre Bridge";
|
||||
const URI = "http://www.reporterre.net/";
|
||||
const DESCRIPTION = "Returns the newest articles.";
|
||||
|
||||
private function ExtractContentReporterre($url) {
|
||||
$html2 = getSimpleHTMLDOM($url);
|
||||
|
||||
foreach($html2->find('div[style=text-align:justify]') as $e) {
|
||||
$text = $e->outertext;
|
||||
}
|
||||
|
||||
$html2->clear();
|
||||
unset ($html2);
|
||||
|
||||
// Replace all relative urls with absolute ones
|
||||
$text = preg_replace('/(href|src)(\=[\"\'])(?!http)([^"\']+)/ims', "$1$2" . self::URI . "$3", $text);
|
||||
|
||||
$text = strip_tags($text, '<p><br><a><img>');
|
||||
return $text;
|
||||
}
|
||||
|
||||
public function collectData(){
|
||||
$html = getSimpleHTMLDOM(self::URI.'spip.php?page=backend') or returnServerError('Could not request Reporterre.');
|
||||
$limit = 0;
|
||||
|
||||
foreach($html->find('item') as $element) {
|
||||
if($limit < 5) {
|
||||
$item = array();
|
||||
$item['title'] = html_entity_decode($element->find('title', 0)->plaintext);
|
||||
$item['timestamp'] = strtotime($element->find('dc:date', 0)->plaintext);
|
||||
$item['uri'] = $element->find('guid', 0)->innertext;
|
||||
$item['content'] = html_entity_decode($this->ExtractContentReporterre($item['uri']));
|
||||
$this->items[] = $item;
|
||||
$limit++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
22
bridges/Rue89Bridge.php
Normal file
22
bridges/Rue89Bridge.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
class Rue89Bridge extends FeedExpander {
|
||||
|
||||
const MAINTAINER = "pit-fgfjiudghdf";
|
||||
const NAME = "Rue89";
|
||||
const URI = "http://rue89.nouvelobs.com/";
|
||||
const DESCRIPTION = "Returns the 5 newest posts from Rue89 (full text)";
|
||||
|
||||
protected function parseItem($item){
|
||||
$item = parent::parseItem($item);
|
||||
|
||||
$url = "http://api.rue89.nouvelobs.com/export/mobile2/node/" . str_replace(" ", "", substr($item['uri'], -8)) . "/full";
|
||||
$datas = json_decode(getContents($url), true);
|
||||
$item['content'] = $datas['node']['body'];
|
||||
|
||||
return $item;
|
||||
}
|
||||
|
||||
public function collectData(){
|
||||
$this->collectExpandableDatas('http://api.rue89.nouvelobs.com/feed');
|
||||
}
|
||||
}
|
12
bridges/Rule34Bridge.php
Normal file
12
bridges/Rule34Bridge.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
require_once('GelbooruBridge.php');
|
||||
|
||||
class Rule34Bridge extends GelbooruBridge{
|
||||
|
||||
const MAINTAINER = "mitsukarenai";
|
||||
const NAME = "Rule34";
|
||||
const URI = "http://rule34.xxx/";
|
||||
const DESCRIPTION = "Returns images from given page";
|
||||
|
||||
const PIDBYPAGE=50;
|
||||
}
|
10
bridges/Rule34pahealBridge.php
Normal file
10
bridges/Rule34pahealBridge.php
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
require_once('Shimmie2Bridge.php');
|
||||
|
||||
class Rule34pahealBridge extends Shimmie2Bridge{
|
||||
|
||||
const MAINTAINER = "mitsukarenai";
|
||||
const NAME = "Rule34paheal";
|
||||
const URI = "http://rule34.paheal.net/";
|
||||
const DESCRIPTION = "Returns images from given page";
|
||||
}
|
12
bridges/SafebooruBridge.php
Normal file
12
bridges/SafebooruBridge.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
require_once('GelbooruBridge.php');
|
||||
|
||||
class SafebooruBridge extends GelbooruBridge{
|
||||
|
||||
const MAINTAINER = "mitsukarenai";
|
||||
const NAME = "Safebooru";
|
||||
const URI = "http://safebooru.org/";
|
||||
const DESCRIPTION = "Returns images from given page";
|
||||
|
||||
const PIDBYPAGE=40;
|
||||
}
|
11
bridges/SakugabooruBridge.php
Normal file
11
bridges/SakugabooruBridge.php
Normal file
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
require_once('MoebooruBridge.php');
|
||||
|
||||
class SakugabooruBridge extends MoebooruBridge{
|
||||
|
||||
const MAINTAINER = "mitsukarenai";
|
||||
const NAME = "Sakugabooru";
|
||||
const URI = "http://sakuga.yshi.org/";
|
||||
const DESCRIPTION = "Returns images from given page";
|
||||
|
||||
}
|
37
bridges/ScmbBridge.php
Normal file
37
bridges/ScmbBridge.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
class ScmbBridge extends BridgeAbstract{
|
||||
|
||||
const MAINTAINER = "Astalaseven";
|
||||
const NAME = "Se Coucher Moins Bête Bridge";
|
||||
const URI = "http://secouchermoinsbete.fr/";
|
||||
const CACHE_TIMEOUT = 21600; // 6h
|
||||
const DESCRIPTION = "Returns the newest anecdotes.";
|
||||
|
||||
public function collectData(){
|
||||
$html = '';
|
||||
$html = getSimpleHTMLDOM(self::URI)
|
||||
or returnServerError('Could not request Se Coucher Moins Bete.');
|
||||
|
||||
foreach($html->find('article') as $article) {
|
||||
$item = array();
|
||||
$item['uri'] = self::URI.$article->find('p.summary a',0)->href;
|
||||
$item['title'] = $article->find('header h1 a',0)->innertext;
|
||||
|
||||
$article->find('span.read-more',0)->outertext=''; // remove text "En savoir plus" from anecdote content
|
||||
$content = $article->find('p.summary a',0)->innertext;
|
||||
$content =substr($content,0,strlen($content)-17); // remove superfluous spaces at the end
|
||||
|
||||
// get publication date
|
||||
$str_date = $article->find('time',0)->datetime;
|
||||
list($date, $time) = explode(' ', $str_date);
|
||||
list($y, $m, $d) = explode('-', $date);
|
||||
list($h, $i) = explode(':', $time);
|
||||
$timestamp = mktime($h,$i,0,$m,$d,$y);
|
||||
$item['timestamp'] = $timestamp;
|
||||
|
||||
|
||||
$item['content'] = $content;
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
}
|
33
bridges/ScoopItBridge.php
Normal file
33
bridges/ScoopItBridge.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
class ScoopItBridge extends BridgeAbstract{
|
||||
|
||||
const MAINTAINER = "Pitchoule";
|
||||
const NAME = "ScoopIt";
|
||||
const URI = "http://www.scoop.it/";
|
||||
const CACHE_TIMEOUT = 21600; // 6h
|
||||
const DESCRIPTION = "Returns most recent results from ScoopIt.";
|
||||
|
||||
const PARAMETERS = array( array(
|
||||
'u'=>array(
|
||||
'name'=>'keyword',
|
||||
'required'=>true
|
||||
)
|
||||
));
|
||||
|
||||
public function collectData(){
|
||||
$this->request = $this->getInput('u');
|
||||
$link = self::URI.'search?q=' .urlencode($this->getInput('u'));
|
||||
|
||||
$html = getSimpleHTMLDOM($link)
|
||||
or returnServerError('Could not request ScoopIt. for : ' . $link);
|
||||
|
||||
foreach($html->find('div.post-view') as $element) {
|
||||
$item = array();
|
||||
$item['uri'] = $element->find('a', 0)->href;
|
||||
$item['title'] = preg_replace('~[[:cntrl:]]~', '', $element->find('div.tCustomization_post_title',0)->plaintext);
|
||||
$item['content'] = preg_replace('~[[:cntrl:]]~', '', $element->find('div.tCustomization_post_description', 0)->plaintext);
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
78
bridges/SensCritiqueBridge.php
Normal file
78
bridges/SensCritiqueBridge.php
Normal file
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
class SensCritiqueBridge extends BridgeAbstract {
|
||||
|
||||
const MAINTAINER = "kranack";
|
||||
const NAME = "Sens Critique";
|
||||
const URI = "http://www.senscritique.com/";
|
||||
const CACHE_TIMEOUT = 21600; // 6h
|
||||
const DESCRIPTION = "Sens Critique news";
|
||||
|
||||
const PARAMETERS = array( array(
|
||||
'm'=>array(
|
||||
'name'=>'Movies',
|
||||
'type'=>'checkbox'
|
||||
),
|
||||
's'=>array(
|
||||
'name'=>'Series',
|
||||
'type'=>'checkbox'
|
||||
),
|
||||
'g'=>array(
|
||||
'name'=>'Video Games',
|
||||
'type'=>'checkbox'
|
||||
),
|
||||
'b'=>array(
|
||||
'name'=>'Books',
|
||||
'type'=>'checkbox'
|
||||
),
|
||||
'bd'=>array(
|
||||
'name'=>'BD',
|
||||
'type'=>'checkbox'
|
||||
),
|
||||
'mu'=>array(
|
||||
'name'=>'Music',
|
||||
'type'=>'checkbox'
|
||||
)
|
||||
));
|
||||
|
||||
public function collectData(){
|
||||
$categories=array();
|
||||
foreach(self::PARAMETERS[$this->queriedContext] as $category=>$properties){
|
||||
if($this->getInput($category)){
|
||||
$uri=self::URI;
|
||||
switch($category){
|
||||
case 'm': $uri.='films/cette-semaine'; break;
|
||||
case 's': $uri.='series/actualite'; break;
|
||||
case 'g': $uri.='jeuxvideo/actualite'; break;
|
||||
case 'b': $uri.='livres/actualite'; break;
|
||||
case 'bd': $uri.='bd/actualite'; break;
|
||||
case 'mu': $uri.='musique/actualite'; break;
|
||||
}
|
||||
$html = getSimpleHTMLDOM($uri)
|
||||
or returnServerError('No results for this query.');
|
||||
$list = $html->find('ul.elpr-list', 0);
|
||||
|
||||
$this->extractDataFromList($list);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function extractDataFromList($list) {
|
||||
if ($list === null) {
|
||||
returnClientError('Cannot extract data from list');
|
||||
}
|
||||
|
||||
foreach ($list->find('li') as $movie) {
|
||||
$item = array();
|
||||
$item['author'] = htmlspecialchars_decode($movie->find('.elco-title a', 0)->plaintext, ENT_QUOTES) . ' ' . $movie->find('.elco-date', 0)->plaintext;
|
||||
$item['title'] = $movie->find('.elco-title a', 0)->plaintext . ' ' . $movie->find('.elco-date', 0)->plaintext;
|
||||
$item['content'] = '<em>' . $movie->find('.elco-original-title', 0)->plaintext . '</em><br><br>' .
|
||||
$movie->find('.elco-baseline', 0)->plaintext . '<br>' .
|
||||
$movie->find('.elco-baseline', 1)->plaintext . '<br><br>' .
|
||||
$movie->find('.elco-description', 0)->plaintext . '<br><br>' .
|
||||
trim($movie->find('.erra-ratings .erra-global', 0)->plaintext) . ' / 10';
|
||||
$item['id'] = $this->getURI() . $movie->find('.elco-title a', 0)->href;
|
||||
$item['uri'] = $this->getURI() . $movie->find('.elco-title a', 0)->href;
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
}
|
75
bridges/SexactuBridge.php
Normal file
75
bridges/SexactuBridge.php
Normal file
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
class SexactuBridge extends BridgeAbstract{
|
||||
|
||||
const MAINTAINER = "Riduidel";
|
||||
const NAME = "Sexactu";
|
||||
const URI = "https://www.gqmagazine.fr";
|
||||
const CACHE_TIMEOUT = 7200; // 2h
|
||||
const DESCRIPTION = "Sexactu via rss-bridge";
|
||||
|
||||
public function collectData(){
|
||||
$find = array('janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet', 'août', 'septembre', 'novembre', 'décembre');
|
||||
$replace = array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December');
|
||||
|
||||
$html = getSimpleHTMLDOM($this->getURI()) or returnServerError('Could not request '.$this->getURI());
|
||||
|
||||
foreach($html->find('.content-holder') as $contentHolder) {
|
||||
// only use first list as second one only contains pages numbers
|
||||
$articles = $contentHolder->find('ul', 0);
|
||||
foreach($articles->find('li') as $element) {
|
||||
// if you ask about that method_exists, there seems to be a bug in simple html dom
|
||||
// see stackoverflow for more details : http://stackoverflow.com/a/10828479/15619
|
||||
if(is_object($element)) {
|
||||
$item = array();
|
||||
// various metadata
|
||||
$titleBlock = $element->find('.title-holder', 0);
|
||||
if(is_object($titleBlock)) {
|
||||
$titleDetails = $titleBlock->find('.article-title',0);
|
||||
$titleData = $titleDetails->find('h2', 0)->find('a',0);
|
||||
$titleTimestamp =$titleDetails->find('h4',0);
|
||||
$item['title'] = $this->correctCase(trim($titleData->innertext));
|
||||
$item['uri'] = self::URI.$titleData->href;
|
||||
|
||||
// Fugly date parsing due to the fact my DNS-323 doesn't support php intl extension
|
||||
$dateText = $titleTimestamp->innertext;
|
||||
$dateText = substr($dateText, strpos($dateText,',')+1);
|
||||
$dateText = str_replace($find, $replace, strtolower($dateText));
|
||||
$date = strtotime($dateText);
|
||||
$item['timestamp'] = $date;
|
||||
|
||||
$item['author'] = "Maïa Mazaurette";
|
||||
$elementText = $element->find('.text-container', 0);
|
||||
// don't forget to replace images server url with gq one
|
||||
foreach($elementText->find('img') as $image) {
|
||||
$image->src = self::URI.$image->src;
|
||||
}
|
||||
$item['content'] = $elementText->innertext;
|
||||
$this->items[] = $item;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getURI(){
|
||||
return self::URI.'/sexactu';
|
||||
}
|
||||
|
||||
private function correctCase($str) {
|
||||
$sentences=explode('.', mb_strtolower($str, "UTF-8"));
|
||||
$str="";
|
||||
$sep="";
|
||||
foreach ($sentences as $sentence)
|
||||
{
|
||||
//upper case first char
|
||||
$sentence=ucfirst(trim($sentence));
|
||||
|
||||
//append sentence to output
|
||||
$str=$str.$sep.$sentence;
|
||||
$sep=". ";
|
||||
}
|
||||
return $str;
|
||||
}
|
||||
}
|
109
bridges/ShanaprojectBridge.php
Normal file
109
bridges/ShanaprojectBridge.php
Normal file
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
class ShanaprojectBridge extends BridgeAbstract {
|
||||
const MAINTAINER = 'logmanoriginal';
|
||||
const NAME = 'Shanaproject Bridge';
|
||||
const URI = 'http://www.shanaproject.com';
|
||||
const DESCRIPTION = 'Returns a list of anime from the current Season Anime List';
|
||||
|
||||
// Returns an html object for the Season Anime List (latest season)
|
||||
private function LoadSeasonAnimeList(){
|
||||
// First we need to find the URI to the latest season from the 'seasons' page searching for 'Season Anime List'
|
||||
$html = getSimpleHTMLDOM($this->getURI() . '/seasons');
|
||||
if(!$html)
|
||||
returnServerError('Could not load \'seasons\' page!');
|
||||
|
||||
$season = $html->find('div.follows_menu/a', 1);
|
||||
if(!$season)
|
||||
returnServerError('Could not find \'Season Anime List\'!');
|
||||
|
||||
$html = getSimpleHTMLDOM($this->getURI() . $season->href);
|
||||
if(!$html)
|
||||
returnServerError('Could not load \'Season Anime List\' from \'' . $season->innertext . '\'!');
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
// Extracts the anime title
|
||||
private function ExtractAnimeTitle($anime){
|
||||
$title = $anime->find('a', 0);
|
||||
if(!$title)
|
||||
returnServerError('Could not find anime title!');
|
||||
return trim($title->innertext);
|
||||
}
|
||||
|
||||
// Extracts the anime URI
|
||||
private function ExtractAnimeURI($anime){
|
||||
$uri = $anime->find('a', 0);
|
||||
if(!$uri)
|
||||
returnServerError('Could not find anime URI!');
|
||||
return $this->getURI() . $uri->href;
|
||||
}
|
||||
|
||||
// Extracts the anime release date (timestamp)
|
||||
private function ExtractAnimeTimestamp($anime){
|
||||
$timestamp = $anime->find('span.header_info_block', 1);
|
||||
if(!$timestamp)
|
||||
returnServerError('Could not find anime timestamp!');
|
||||
return strtotime($timestamp->innertext);
|
||||
}
|
||||
|
||||
// Extracts the anime studio name (author)
|
||||
private function ExtractAnimeAuthor($anime){
|
||||
$author = $anime->find('span.header_info_block', 2);
|
||||
if(!$author)
|
||||
return; // Sometimes the studio is unknown, so leave empty
|
||||
return trim($author->innertext);
|
||||
}
|
||||
|
||||
// Extracts the episode information (x of y released)
|
||||
private function ExtractAnimeEpisodeInformation($anime){
|
||||
$episode = $anime->find('div.header_info_episode', 0);
|
||||
if(!$episode)
|
||||
returnServerError('Could not find anime episode information!');
|
||||
return preg_replace('/\r|\n/', ' ', $episode->plaintext);
|
||||
}
|
||||
|
||||
// Extracts the background image
|
||||
private function ExtractAnimeBackgroundImage($anime){
|
||||
// Getting the picture is a little bit tricky as it is part of the style.
|
||||
// Luckily the style is part of the parent div :)
|
||||
|
||||
if(preg_match("/url\(\/\/([^\)]+)\)/i", $anime->parent->style, $matches))
|
||||
return $matches[1];
|
||||
|
||||
returnServerError('Could not extract background image!');
|
||||
}
|
||||
|
||||
// Builds an URI to search for a specific anime (subber is left empty)
|
||||
private function BuildAnimeSearchURI($anime){
|
||||
return $this->getURI() . '/search/?title=' . urlencode($this->ExtractAnimeTitle($anime)) . '&subber=';
|
||||
}
|
||||
|
||||
// Builds the content string for a given anime
|
||||
private function BuildAnimeContent($anime){
|
||||
// We'll use a template string to place our contents
|
||||
return '<a href="' . $this->ExtractAnimeURI($anime) . '">
|
||||
<img src="http://' . $this->ExtractAnimeBackgroundImage($anime) . '" alt="' . htmlspecialchars($this->ExtractAnimeTitle($anime)) . '" style="border: 1px solid black">
|
||||
</a><br>
|
||||
<p>' . $this->ExtractAnimeEpisodeInformation($anime) . '</p><br>
|
||||
<p><a href="' . $this->BuildAnimeSearchURI($anime) . '">Search episodes</a></p>';
|
||||
}
|
||||
|
||||
public function collectData(){
|
||||
$html = $this->LoadSeasonAnimeList();
|
||||
|
||||
$animes = $html->find('div.header_display_box_info');
|
||||
if(!$animes)
|
||||
returnServerError('Could not find anime headers!');
|
||||
|
||||
foreach($animes as $anime){
|
||||
$item = array();
|
||||
$item['title'] = $this->ExtractAnimeTitle($anime);
|
||||
$item['author'] = $this->ExtractAnimeAuthor($anime);
|
||||
$item['uri'] = $this->ExtractAnimeURI($anime);
|
||||
$item['timestamp'] = $this->ExtractAnimeTimestamp($anime);
|
||||
$item['content'] = $this->BuildAnimeContent($anime);
|
||||
$this->items[] = $item;
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user