summaryrefslogtreecommitdiffstats
path: root/news
diff options
context:
space:
mode:
Diffstat (limited to 'news')
-rw-r--r--news/.gitignore1
-rwxr-xr-xnews/GfindFeeds4bot17
-rw-r--r--news/feeds2
l---------news/ircasy.py1
-rw-r--r--news/new_feeds183
-rw-r--r--news/newsbot.js272
-rw-r--r--news/newsbot.py259
-rw-r--r--news/package.json32
8 files changed, 767 insertions, 0 deletions
diff --git a/news/.gitignore b/news/.gitignore
new file mode 100644
index 00000000..07e6e472
--- /dev/null
+++ b/news/.gitignore
@@ -0,0 +1 @@
+/node_modules
diff --git a/news/GfindFeeds4bot b/news/GfindFeeds4bot
new file mode 100755
index 00000000..a5439c5a
--- /dev/null
+++ b/news/GfindFeeds4bot
@@ -0,0 +1,17 @@
+#! /bin/sh
+# usage: GfindFeeds4bot QUERY
+set -euf
+
+export query="$1"
+export data="$(
+ curl -sS "https://www.google.com/uds/GfindFeeds?v=1.0&q=$query"
+)"
+
+node <<EOF
+ query = process.env.query
+ data = JSON.parse(process.env.data)
+
+ data.responseData.entries.forEach(function (entry, index) {
+ console.log(query + index + '|' + entry.url)
+ })
+EOF
diff --git a/news/feeds b/news/feeds
new file mode 100644
index 00000000..50fe0667
--- /dev/null
+++ b/news/feeds
@@ -0,0 +1,2 @@
+HN|http://news.ycombinator.com/rss
+Fefe|http://blog.fefe.de/rss.xml
diff --git a/news/ircasy.py b/news/ircasy.py
new file mode 120000
index 00000000..68231591
--- /dev/null
+++ b/news/ircasy.py
@@ -0,0 +1 @@
+../Reaktor/IRC/ircasy.py \ No newline at end of file
diff --git a/news/new_feeds b/news/new_feeds
new file mode 100644
index 00000000..a5de8d72
--- /dev/null
+++ b/news/new_feeds
@@ -0,0 +1,183 @@
+aje|http://www.aljazeera.com/Services/Rss/?PostingId=2007731105943979989|#news
+aktuelle_themen|http://bundestag.de/service/rss/Bundestag_Aktuelle_Themen.rss|#news #bundestag
+allafrica|http://allafrica.com/tools/headlines/rdf/latest/headlines.rdf|#news
+anon|http://anoninsiders.net/feed/|#news
+antirez|http://antirez.com/rss|#news
+arbor|http://feeds2.feedburner.com/asert/|#news
+archlinux|http://www.archlinux.org/feeds/news/|#news
+ars|http://feeds.arstechnica.com/arstechnica/index?format=xml|#news
+asiaone_asia|http://news.asiaone.com/rss/asia|#news
+asiaone_business|http://business.asiaone.com/rss.xml|#news
+asiaone_sci|http://news.asiaone.com/rss/science-and-tech|#news
+asiaone_world|http://news.asiaone.com/rss/world|#news
+augustl|http://augustl.com/atom.xml|#news
+bbc|http://feeds.bbci.co.uk/news/rss.xml|#news
+bdt_drucksachen|http://www.bundestag.de/dip21rss/bundestag_drucksachen.rss|#news #bundestag
+bdt_plenarproto|http://www.bundestag.de/rss_feeds/plenarprotokolle.rss|#news #bundestag
+bdt_pressemitteilungen|http://bundestag.de/service/rss/Bundestag_Presse.rss|#news #bundestag
+bdt_wd|http://bundestag.de/service/rss/Bundestag_WD.rss|#news #bundestag
+bitcoinboard|http://bitcoinboard.net/feed/|#news #financial
+bitcoinpakistan|https://bitcoinspakistan.com/feed/|#news #financial
+businessweek|http://www.businessweek.com/feeds/homepage.rss|#news
+cancer|http://feeds.feedburner.com/ncinewsreleases?format=xml|#news
+carta|http://feeds2.feedburner.com/carta-standard-rss|#news
+catholic_news|http://feeds.feedburner.com/catholicnewsagency/dailynews|#news
+cbc_busi|http://rss.cbc.ca/lineup/business.xml|#news
+cbc_offbeat|http://www.cbc.ca/cmlink/rss-offbeat|#news
+cbc_pol|http://rss.cbc.ca/lineup/politics.xml|#news
+cbc_tech|http://rss.cbc.ca/lineup/technology.xml|#news
+cbc_top|http://rss.cbc.ca/lineup/topstories.xml|#news
+ccc|http://www.ccc.de/rss/updates.rdf|#news
+chan_b|http://boards.4chan.org/b/index.rss|#brainfuck
+chan_biz|http://boards.4chan.org/biz/index.rss|#news #brainfuck
+chan_g|http://boards.4chan.org/g/index.rss|#news #brainfuck
+chan_int|http://boards.4chan.org/int/index.rss|#news #brainfuck
+cna|http://www.channelnewsasia.com/starterkit/servlet/cna/rss/home.xml|#news
+cryptanalysis|https://cryptanalys.is/rss.php|#news
+coindesk|http://feeds.feedburner.com/CoinDesk?format=xml|#news #financial
+coinspotting|http://coinspotting.com/rss|#news #financial
+cryptoarticles|http://www.cryptoarticles.com/crypto-news?format=rss|#news
+cryptocoinsnews|http://www.cryptocoinsnews.com/feed/|#news #financial
+cryptogon|http://www.cryptogon.com/?feed=rss2|#news
+csm|http://rss.csmonitor.com/feeds/csm|#news
+csm_world|http://rss.csmonitor.com/feeds/world|#news
+cyberguerrilla|https://www.cyberguerrilla.org/a/2012/?feed=rss2|#news
+danisch|http://www.danisch.de/blog/feed/|#news
+dwn|http://deutsche-wirtschafts-nachrichten.de/feed/customfeed/|#news
+ecat|http://ecat.com/feed|#news
+eia_press|http://www.eia.gov/rss/press_rss.xml|#news
+eia_today|http://www.eia.gov/rss/todayinenergy.xml|#news
+embargowatch|https://embargowatch.wordpress.com/feed/|#news
+ethereum-comments|http://blog.ethereum.org/comments/feed|#news
+ethereum|http://blog.ethereum.org/feed|#news
+europa_ric|http://ec.europa.eu/research/infocentre/rss/infocentre-rss.xml|#news
+eu_survei|http://www.eurosurveillance.org/public/RSSFeed/RSS.aspx|#news
+exploitdb|http://www.exploit-db.com/rss.xml|#news
+fars|http://www.farsnews.com/rss.php|#news #test
+faz_feui|http://www.faz.net/rss/aktuell/feuilleton/|#news
+faz_politik|http://www.faz.net/rss/aktuell/politik/|#news
+faz_wirtschaft|http://www.faz.net/rss/aktuell/wirtschaft/|#news #financial
+fbi|http://www.fbi.gov/homepage/RSS|#news #bullerei
+fbi_news|http://www.fbi.gov/news/news_blog/rss.xml|#news
+fbi_press|http://www.fbi.gov/news/current/rss.xml|#news #bullerei
+fbi_stories|http://www.fbi.gov/news/stories/all-stories/rss.xml|#news #bullerei
+fedreserve|http://www.federalreserve.gov/feeds/press_all.xml|#news #financial
+fefe|http://blog.fefe.de/rss.xml|#news
+forbes|http://www.forbes.com/forbes/feed2/|#news
+forbes_realtime|http://www.forbes.com/real-time/feed2/|#news
+fox|http://feeds.foxnews.com/foxnews/latest|#news
+fvwm|http://freecode.com/projects/fvwm/releases.atom|#news
+geheimorganisation|http://geheimorganisation.org/feed/|#news
+GerForPol|http://www.german-foreign-policy.com/de/news/rss-2.0|#news
+gmanet|http://www.gmanetwork.com/news/rss/news|#news
+golem|http://www.golem.de/rss.php?feed=RSS1.0|#news
+google|http://news.google.com/?output=rss|#news
+guardian_uk|http://feeds.theguardian.com/theguardian/uk-news/rss|#news
+gulli|http://ticker.gulli.com/rss/|#news
+handelsblatt|http://www.handelsblatt.com/contentexport/feed/schlagzeilen|#news #financial
+heise|http://heise.de.feedsportal.com/c/35207/f/653902/index.rss|#news
+hindu_business|http://www.thehindubusinessline.com/?service=rss|#news #financial
+hindu|http://www.thehindu.com/?service=rss|#news
+hintergrund|http://www.hintergrund.de/index.php?option=com_bca-rss-syndicator&feed_id=8|#news
+HN|http://news.ycombinator.com/rss|#news
+ign|http://feeds.ign.com/ign/all|#news
+independent|http://www.independent.com/rss/headlines/|#news
+indymedia|http://de.indymedia.org/RSS/newswire.xml|#news
+info_libera|http://www.informationliberation.com/rss.xml|#news
+klagen-gegen-rundfuckbeitrag|http://klagen-gegen-rundfunkbeitrag.blogspot.com/feeds/posts/default|#news
+korea_herald|http://www.koreaherald.com/rss_xml.php|#news
+linuxinsider|http://www.linuxinsider.com/perl/syndication/rssfull.pl|#news
+lisp|http://planet.lisp.org/rss20.xml|#news
+liveleak|http://www.liveleak.com/rss|#news
+lolmythesis|http://lolmythesis.com/rss|#news
+LtU|http://lambda-the-ultimate.org/rss.xml|#news
+lukepalmer|http://lukepalmer.wordpress.com/feed/|#news
+mit|http://web.mit.edu/newsoffice/rss-feeds.feed?type=rss|#news
+mongrel2_master|https://github.com/zedshaw/mongrel2/commits/master.atom|#news
+nds|http://www.nachdenkseiten.de/?feed=atom|#news
+netzpolitik|https://netzpolitik.org/feed/|#news
+newsbtc|http://newsbtc.com/feed/|#news #financial
+nnewsg|http://www.net-news-global.net/rss/rssfeed.xml|#news
+npr_busi|http://www.npr.org/rss/rss.php?id=1006|#news
+npr_headlines|http://www.npr.org/rss/rss.php?id=1001|#news
+npr_pol|http://www.npr.org/rss/rss.php?id=1012|#news
+npr_world|http://www.npr.org/rss/rss.php?id=1004|#news
+nsa|http://www.nsa.gov/rss.shtml|#news #bullerei
+nytimes|http://rss.nytimes.com/services/xml/rss/nyt/World.xml|#news
+phys|http://phys.org/rss-feed/|#news
+piraten|https://www.piratenpartei.de/feed/|#news
+polizei_berlin|http://www.berlin.de/polizei/presse-fahndung/_rss_presse.xml|#news #bullerei
+presse_polizei|http://www.presseportal.de/rss/polizei.rss2|#news #bullerei
+presseportal|http://www.presseportal.de/rss/presseportal.rss2|#news
+prisonplanet|http://prisonplanet.com/feed.rss|#news
+proofmarket|https://proofmarket.org/feed_problem|#news
+rawstory|http://www.rawstory.com/rs/feed/|#news
+reddit_4chan|http://www.reddit.com/r/4chan/new/.rss|#news #brainfuck
+reddit_anticonsum|http://www.reddit.com/r/Anticonsumption/new/.rss|#news
+reddit_btc|http://www.reddit.com/r/Bitcoin/new/.rss|#news #financial
+reddit_consp|http://reddit.com/r/conspiracy/.rss|#news
+reddit_sci|http://www.reddit.com/r/science/.rss|#news
+reddit_tech|http://www.reddit.com/r/technology/.rss|#news
+reddit_tpp|http://www.reddit.com/r/twitchplayspokemon/.rss|#news #tpp
+reddit_world|http://www.reddit.com/r/worldnews/.rss|#news
+r-ethereum|http://www.reddit.com/r/ethereum/.rss|#news
+reuters|http://feeds.reuters.com/Reuters/worldNews|#news
+reuters-odd|http://feeds.reuters.com/reuters/oddlyEnoughNews?format=xml|#news
+rt|http://rt.com/rss/news/|#news
+schallurauch|http://feeds.feedburner.com/SchallUndRauch|#news
+sciencemag|http://news.sciencemag.org/rss/current.xml|#news
+scmp|http://www.scmp.com/rss/91/feed|#news
+sec-db|http://feeds.security-database.com/SecurityDatabaseToolsWatch|#news
+shackspace|http://shackspace.de/?feed=rss2|#news
+shz_news|http://www.shz.de/nachrichten/newsticker/rss|#news
+sky_busi|http://news.sky.com/feeds/rss/business.xml|#news
+sky_pol|http://news.sky.com/feeds/rss/politics.xml|#news
+sky_strange|http://news.sky.com/feeds/rss/strange.xml|#news
+sky_tech|http://news.sky.com/feeds/rss/technology.xml|#news
+sky_world|http://news.sky.com/feeds/rss/world.xml|#news
+slashdot|http://rss.slashdot.org/Slashdot/slashdot|#news
+slate|http://feeds.slate.com/slate|#news
+spiegel_eil|http://www.spiegel.de/schlagzeilen/eilmeldungen/index.rss|#news
+spiegelfechter|http://feeds.feedburner.com/DerSpiegelfechter?format=xml|#news
+spiegel_top|http://www.spiegel.de/schlagzeilen/tops/index.rss|#news
+standardmedia_ke|http://www.standardmedia.co.ke/rss/headlines.php|#news
+stern|http://www.stern.de/feed/standard/all/|#news
+stz|http://www.stuttgarter-zeitung.de/rss/topthemen.rss.feed|#news
+sz_politik|http://rss.sueddeutsche.de/rss/Politik|#news
+sz_wirtschaft|http://rss.sueddeutsche.de/rss/Wirtschaft|#news #financial
+sz_wissen|http://suche.sueddeutsche.de/rss/Wissen|#news
+tagesschau|http://www.tagesschau.de/newsticker.rdf|#news
+taz|http://taz.de/Themen-des-Tages/!p15;rss/|#news
+telegraph_finance|http://www.telegraph.co.uk/finance/rss|#news #financial
+telegraph_pol|http://www.telegraph.co.uk/news/politics/rss|#news
+telegraph_uk|http://www.telegraph.co.uk/news/uknews/rss|#news
+telegraph_world|http://www.telegraph.co.uk/news/worldnews/rss|#news
+telepolis|http://www.heise.de/tp/rss/news-atom.xml|#news
+the_insider|http://www.theinsider.org/rss/news/headlines-xml.asp|#news
+tigsource|http://www.tigsource.com/feed/|#news
+times|http://www.thetimes.co.uk/tto/news/rss|#news
+tinc|http://tinc-vpn.org/news/index.rss|#news
+topix_b|http://www.topix.com/rss/wire/de/berlin|#news
+torr_bits|http://feeds.feedburner.com/TorrentfreakBits|#news
+torrentfreak|http://feeds.feedburner.com/Torrentfreak|#news
+torr_news|http://feed.torrentfreak.com/Torrentfreak/|#news
+travel_warnings|http://feeds.travel.state.gov/ca/travelwarnings-alerts|#news
+truther|http://truthernews.wordpress.com/feed/|#news
+un_afr|http://www.un.org/apps/news/rss/rss_africa.asp|#news
+un_am|http://www.un.org/apps/news/rss/rss_americas.asp|#news
+un_eu|http://www.un.org/apps/news/rss/rss_europe.asp|#news
+un_me|http://www.un.org/apps/news/rss/rss_mideast.asp|#news
+un_pac|http://www.un.org/apps/news/rss/rss_asiapac.asp|#news
+un_top|http://www.un.org/apps/news/rss/rss_top.asp|#news
+us_math_society|http://www.ams.org/cgi-bin/content/news_items.cgi?rss=1|#news
+vimperator|https://sites.google.com/a/vimperator.org/www/blog/posts.xml|#news
+weechat|http://dev.weechat.org/feed/atom|#news
+wp_world|http://feeds.washingtonpost.com/rss/rss_blogpost|#news
+xkcd|https://xkcd.com/rss.xml|#news
+yahoo|http://news.yahoo.com/rss/|#news
+zdnet|http://www.zdnet.com/news/rss.xml|#news
+reddit_prog|http://www.reddit.com/r/programming/new/.rss|#news
+bmj|[object Object]|#news
+dod|http://www.defense.gov/news/afps2.xml|#news
+greenpeace|http://feeds.feedburner.com/GreenpeaceNews|#news
+painload|https://github.com/krebscode/painload/commits/master.atom|#news
diff --git a/news/newsbot.js b/news/newsbot.js
new file mode 100644
index 00000000..18b5f780
--- /dev/null
+++ b/news/newsbot.js
@@ -0,0 +1,272 @@
+var IRC = require('irc')
+var FeedParser = require('feedparser')
+var Request = require('request')
+var Parse = require('shell-quote').parse
+var FS = require('fs')
+var HTTP = require('http')
+var FormData = require('form-data')
+var URL = require('url')
+
+var irc_server = 'ire.retiolum'
+var master_nick = 'knews'
+var news_channel = '#news'
+var feeds_file = 'new_feeds'
+var feedbot_loop_delay = 60 * 1000 // [ms]
+var feedbot_create_delay = 200 // [ms]
+var url_shortener_host = 'go'
+
+var slaves = {}
+
+function main () {
+ var master = new IRC.Client(irc_server, master_nick, {
+ channels: [ news_channel ],
+ })
+
+ master.on('message' + news_channel, function (nick, text, message) {
+ if (is_talking_to(master_nick, text)) {
+ var request = parse_request(text)
+ if (request) {
+ return run_command(request.method, request.params, function (error, result) {
+ if (error) {
+ return master.say(news_channel, '4' + error)
+ } else {
+ return master.say(news_channel, result)
+ }
+ })
+ }
+ }
+ })
+
+ master.once('registered', function () {
+ // read feeds file and create a feedbot for each entry
+ FS
+ .readFileSync(feeds_file)
+ .toString()
+ .split('\n')
+ //.filter((function () {
+ // var n = 2;
+ // return function () {
+ // return n-- > 0
+ // }
+ //})())
+ .filter(function (line) {
+ return line.length > 0
+ })
+ .forEach(function (line, i) {
+ var parts = line.split('|')
+ if (parts.length !== 3) {
+ console.log('bad new_feeds line ' + lines + ': ' + line)
+ return
+ }
+
+ var nick = parts[0]
+ var uri = parts[1]
+ var channels = parts[2].split(' ')
+
+ setTimeout(function () {
+ return create_feedbot(nick, uri, channels)
+ }, i*feedbot_create_delay)
+ })
+ })
+}
+
+function create_feedbot (nick, uri, channels) {
+ var client = new IRC.Client(irc_server, nick, {
+ channels: channels,
+ autoRejoin: false,
+ })
+
+ slaves[nick] = {
+ client: client,
+ nick: nick,
+ uri: uri,
+ }
+
+ // say text in every joined channel
+ function broadcast (text) {
+ Object.keys(client.chans).forEach(function (channel) {
+ client.say(channel, text)
+ })
+ }
+
+ function broadcast_new_item (item) {
+ return getShortLink(item.link, function (error, shortlink) {
+ return broadcast(item.title + ' ' + shortlink)
+ })
+ }
+
+ client.once('registered', loop_feedparser)
+ client.once('registered', deaf_myself)
+
+ client.on('invite', function (channel, from, message) {
+ client.join(channel, null)
+ })
+
+ client.on('error', function (error) {
+ console.log('Error:', error)
+ })
+
+ // TODO stopping criteria
+ function loop_feedparser () {
+ try {
+ var request = Request(uri)
+ var feedparser = new FeedParser()
+ } catch (error) {
+ return broadcast('4' + error)
+ }
+
+ request.on('error', function (error) {
+ broadcast('4request ' + error)
+ })
+ request.on('response', function (response) {
+ if (response.statusCode !== 200) {
+ return this.emit('error', new Error('Bad status code'))
+ }
+ var output = response
+ switch (response.headers['content-encoding']) {
+ case 'gzip':
+ output = zlib.createGunzip()
+ response.pipe(output)
+ break
+ case 'deflate':
+ output = zlib.createInflate()
+ response.pipe(output)
+ break
+ }
+ this.pipe(feedparser)
+ })
+
+ var items = []
+
+ feedparser.on('error', function (error) {
+ broadcast('4feedparser ' + error)
+ return continue_loop()
+ })
+ feedparser.on('readable', function () {
+ for (var item; item = this.read(); ) {
+ items.push(item)
+ }
+ })
+ feedparser.on('end', function () {
+
+ if (client.lastItems) {
+ items.forEach(function (item) {
+ if (!client.lastItems.hasOwnProperty(item.title)) {
+ broadcast_new_item(item)
+ }
+ })
+ }
+
+ client.lastItems = {}
+ items.forEach(function (item) {
+ client.lastItems[item.title] = true
+ })
+
+ return continue_loop()
+ })
+
+ function continue_loop () {
+ setTimeout(loop_feedparser, feedbot_loop_delay)
+ }
+ }
+ function deaf_myself () {
+ client.send('mode', nick, '+D')
+ }
+}
+
+// return true if text "is talking to" my_nick
+function is_talking_to (my_nick, text) {
+ return text.slice(0, my_nick.length) === my_nick
+ && text[my_nick.length] === ':'
+}
+
+function parse_request (text) {
+ var parse = Parse(text)
+ return {
+ method: parse[1],
+ params: parse.slice(2),
+ }
+}
+
+function run_command (methodname, params, callback) {
+ var method = methods[methodname]
+ if (method) {
+ return method(params, callback)
+ } else {
+ return callback(new Error('dunno what ' + methodname + ' is'));
+ }
+}
+
+function getShortLink (link, callback) {
+ var form = new FormData()
+ try {
+ form.append('uri', link)
+ } catch (err) {
+ console.log('link:', link)
+ throw err
+ }
+
+ var request = HTTP.request({
+ method: 'post',
+ host: url_shortener_host,
+ path: '/',
+ headers: form.getHeaders(),
+ })
+ form.pipe(request)
+
+ request.on('response', function (response) {
+ var data = ''
+ response.on('data', function (chunk) {
+ data += chunk
+ })
+ response.on('end', function () {
+ callback(null, data.replace(/\r\n$/,'') + '#' + URL.parse(link).host)
+ })
+ })
+}
+
+var methods = {}
+methods.add = function (params, callback) {
+ if (slaves.hasOwnProperty(params[0])) {
+ return callback(new Error('name already taken'))
+ } else {
+ create_feedbot(params[0], params[1], [news_channel])
+ return callback(null)
+ }
+}
+methods.del = function (params, callback) {
+ var nick = params[0]
+ if (slaves.hasOwnProperty(nick)) {
+ var slave = slaves[nick]
+ slave.client.disconnect()
+ delete slaves[nick]
+ return callback(null)
+ } else {
+ return callback(new Error('botname not found'))
+ }
+}
+methods.save = function (params, callback) {
+ var feeds = Object.keys(slaves)
+ .map(function (nick) {
+ return slaves[nick]
+ })
+ .map(function (slave) {
+ return [
+ slave.nick,
+ slave.uri,
+ Object.keys(slave.client.chans).join(' '),
+ ].join('|')
+ }).join('\n') + '\n'
+ return FS.writeFile(feeds_file, feeds, function (error) {
+ if (error) {
+ return callback(error)
+ } else {
+ return callback(null, 'Feeds saved')
+ }
+ })
+}
+
+
+if (require.main === module) {
+ main()
+}
diff --git a/news/newsbot.py b/news/newsbot.py
new file mode 100644
index 00000000..2f8bf635
--- /dev/null
+++ b/news/newsbot.py
@@ -0,0 +1,259 @@
+from ircasy import asybot
+import threading
+from asyncore import loop
+import logging
+import os
+import subprocess
+
+import feedparser
+import math
+import re
+import subprocess
+from datetime import datetime
+from time import sleep
+#testbot = NewsBot('ire', 6667, 'crabman23', ['#retiolum'], loglevel=logging.DEBUG)
+
+
+
+## Newsbot Controller Class
+class NewsBot(asybot):
+ def __init__(self, name, channels=['#test'], server='ire', port=6667, timeout=60, loglevel=logging.ERROR, url_shortener='http://localhost'):
+ asybot.__init__(self, server, port, name, channels, loglevel=loglevel)
+ self.to = timeout
+ self.url_shortener = url_shortener
+ self.ctrl_chan = channels[0]
+
+ def send_msg(self, target, msg):
+ for line in msg.split('\n'):
+ self.PRIVMSG(target, line)
+
+ def on_privmsg(self, prefix, command, params, rest):
+ args_array = rest.split()
+ if params[0] == self.nickname:
+ answer = self.read_message(args_array)
+ self.send_msg(prefix.split('!')[0], answer)
+ elif args_array[0].strip(':') == self.nickname:
+ answer = self.read_message(args_array[1:])
+ self.send_msg([params[0]], answer)
+
+ def on_invite(self, prefix, command, params, rest):
+ for chan in rest.split():
+ self.push('JOIN ' + chan)
+ self.channels.append(chan)
+
+ def read_message(self, args):
+ try:
+ if args[0] in [x for x in commands.__dict__.keys() if x.find('_')]:
+ func = getattr(commands, args[0])
+ return func(self, args)
+ else:
+ return 'command not found'
+ except Exception as e:
+ return 'mimimi: ' + str(e)
+
+#Commands of NewsBot
+class commands():
+ def add(self, args):
+ if args[1] not in bots and args[1] != self.nickname:
+ try:
+ bot = RssBot(args[2], args[1], [self.ctrl_chan], url_shortener=self.url_shortener)
+ except Exception as e:
+ return 'add_mimi: ' + str(e)
+ sleep
+ bots[args[1]] = bot
+ bot.start_rss()
+ return "bot " + args[1] + " added"
+ else:
+ return args[1] + ' does already exist'
+
+ def delete(self, args):
+ bots[args[1]].stop()
+ del bots[args[1]]
+ return "bot " + args[1] + " deleted"
+
+ def rename(self, args):
+ if args[1] in bots:
+ if args[2] in bots:
+ return args[2] + ' already taken'
+ else:
+ bots[args[1]].connection.nick(args[2])
+ bots[args[1]].name = args[2]
+ bots[args[2]] = bots[args[1]]
+ del bots[args[1]]
+ return 'renamed ' + args[1] + ' in ' + args[2]
+ else:
+ return args[1] + ' does not exist'
+
+ def save(self, args):
+ output_buffer = ''
+ for bot in bots:
+ if bots[bot].loop:
+ output_buffer += bot + '|' + bots[bot].url + '|' + ' '.join(bots[bot].channels) + '\n'
+
+ F = open(feedfile, "w")
+ F.writelines(output_buffer)
+ F.close()
+
+ return "bots saved to " + feedfile
+
+ def caps(self, args):
+ return ' '.join([x for x in commands.__dict__.keys() if x.find('_')])
+
+ def list(self, args):
+ output_buffer = ''
+ for bot in bots:
+ output_buffer += bot + ' url: ' + bots[bot].url + '\n'
+ return output_buffer
+
+ def info(self, args):
+ if args[1] in bots:
+ output_buffer = ''
+ for data in ['title', 'link', 'updated']:
+ if data in bots[args[1]].feed.feed:
+ output_buffer += data + ': ' + bots[args[1]].feed.feed[data] + '\n'
+ output_buffer += 'lastnew: ' + bots[args[1]].lastnew.isoformat() + '\n'
+ output_buffer += 'rssurl: ' + bots[args[1]].url
+ return output_buffer
+ else:
+ return 'bot not found'
+
+ def search(self, args):
+ output = subprocess.check_output(['./GfindFeeds4bot', args[1]]).decode()
+ return output
+
+ def uptime(self, args):
+ output = subprocess.check_output(['uptime']).decode()
+ return output
+
+
+##RssBot Class
+class RssBot(asybot):
+ def __init__(self, rss, name, chans=['#news'], url_shortener="http://localhost", server='ire', port=6667, timeout=60):
+ try:
+ asybot.__init__(self, server, port, name, chans)
+ except Exception as e:
+ print(e)
+ self.url = rss
+ self.to = timeout
+ self.oldnews = []
+ self.loop = True
+ self.lastnew = datetime.now()
+ self.url_shortener = url_shortener
+ self.retry = True
+
+ def on_nickinuse(*bla):
+ pass
+
+ def start_rss(self):
+ self.upd_loop = threading.Thread(target=self.updateloop)
+ self.upd_loop.start()
+
+ def stop(self):
+ self.disconnect()
+ self.loop = False
+
+ def updateloop(self):
+ failcount=0
+ while True:
+ try:
+ self.feed = feedparser.parse(self.url)
+ for entry in self.feed.entries:
+ self.oldnews.append(entry.link)
+ break
+ except:
+ print(self.nickname + ': rss timeout occured')
+ failcount+=1
+ if failcount>20:
+ print(self.nickname + ' is broken, going to die')
+ self.stop()
+ return
+ while self.loop:
+ try:
+ self.feed = feedparser.parse(self.url)
+ for entry in self.feed.entries:
+ if not entry.link in self.oldnews:
+ #try:
+ # self.send_msg(entry.title + " " + entry.link + " com: " + entry.comments)
+ #except AttributeError:
+ shorturl = self.shortenurl(entry.link)
+ self.sendall(entry.title + ' ' + shorturl)
+ self.oldnews.append(entry.link)
+ self.lastnew = datetime.now()
+ except Exception as e:
+ print(str(datetime.now().hour) + ':' + str(datetime.now().minute) + ' ' + self.nickname + ': ' + str(e))
+ sleep(self.to)
+
+ def shortenurl(self, url):
+ while True:
+ try:
+ shorturl = subprocess.check_output(["curl", "-sS", "-F", "uri=" + url, self.url_shortener]).decode().strip('\n').strip('\r') + '#' + url.partition('://')[2].partition('/')[0]
+ return shorturl
+ except:
+ print('url shortener error')
+ sleep(1)
+
+ def last(self, target, num):
+ for feed in [x for x in self.feed.entries][:num]:
+ self.send_msg(target, feed.title + ' ' + self.shortenurl(feed.link))
+
+ def sendall(self, string):
+ try:
+ self.send_msg(self.channels, string)
+ except Exception as e:
+ print(self.nickname + ': failed sending all to ' + str(self.channels) + ' because of ' + str(e));
+
+ def send_msg(self, target, string):
+ if self.connected:
+ for line in string.split('\n'):
+ while len(line)>0:
+ if len(line) < 450:
+ self.PRIVMSG(target, line)
+ line = ''
+ else:
+ space = line.rfind(" ", 1, 450)
+ self.PRIVMSG(target, line[:space])
+ line=line[space:]
+ else:
+ self.reconnect()
+ while not self.connected:
+ print(self.nickname + ' waiting for reconnect')
+ sleep(10)
+ self.send_msg(target, string)
+
+ def on_invite(self, prefix, command, params, rest):
+ for chan in rest.split():
+ self.push('JOIN ' + chan)
+ self.channels.append(chan)
+
+ def on_welcome(self, prefix, command, params, rest):
+ asybot.on_welcome(self, prefix, command, params, rest)
+ self.push('MODE ' + self.nickname + ' +D')
+
+feedfile = 'new_feeds'
+url_shortener = 'http://go'
+init_channels = ['#news']
+
+bots = {}
+knews = NewsBot('knews', init_channels, url_shortener=url_shortener)
+
+#config file reading
+F = open(feedfile, "r")
+lines = F.readlines()
+F.close()
+
+for line in lines:
+ line = line.strip('\n')
+ linear = line.split('|')
+ bot = RssBot(linear[1], linear[0], linear[2].split(), url_shortener=url_shortener)
+ bot.start_rss()
+ bots[linear[0]] = bot
+
+def thread_handler():
+ while True:
+ try:
+ loop()
+ except Exception as e:
+ print('ohoh ' + e)
+
+th = threading.Thread(target=thread_handler)
+th.start()
diff --git a/news/package.json b/news/package.json
new file mode 100644
index 00000000..52c19177
--- /dev/null
+++ b/news/package.json
@@ -0,0 +1,32 @@
+{
+ "name": "news",
+ "version": "0.0.0",
+ "description": "",
+ "main": "newsbot.js",
+ "dependencies": {
+ "feedparser": "*",
+ "form-data": "*",
+ "irc": "*",
+ "request": "*",
+ "shell-quote": "*"
+ },
+ "devDependencies": {},
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/krebscode/painload"
+ },
+ "keywords": [
+ "irc",
+ "news",
+ "feed"
+ ],
+ "author": "krebs",
+ "license": "WTFPLv2",
+ "bugs": {
+ "url": "https://github.com/krebscode/painload/issues"
+ },
+ "homepage": "https://github.com/krebscode/painload"
+}