diff --git a/LIST_COMMANDS.md b/LIST_COMMANDS.md index 560a83d..360b918 100644 --- a/LIST_COMMANDS.md +++ b/LIST_COMMANDS.md @@ -152,10 +152,10 @@ > Prints stats on the Twitter account set for the channel. > > restricted to /TWITTER -# Twitter & RSS Feeds monitoring commands - * (Un)Follow and (Un)Filter available only to GLOBAL_USERS and chan's USERS +# Twitter, RSS Feeds & Webpages monitoring commands + * (Un)Follow, (Un)Filter and Monitor available only to GLOBAL_USERS and chan's USERS * Others available to anyone - * **Exclude regexp :** `'(u?n?f(ollow|ilter)|list|newsurl|last(tweet|news)|digest)'` + * **Exclude regexp :** `'(u?n?f(ollow|ilter)|u?n?monitor|list|newsurl|last(tweet|news)|digest)'` * **List :** + `follow ` @@ -168,6 +168,16 @@ > Asks me to stop following and displaying elements from a RSS named <name>, or tweets matching <text> or from <@user>. > > restricted to /AUTH + + `monitor ` + + > Asks me to regularily check and tell if the webpage at <url> and identified as <name> changes. + > > restricted to /AUTH + + + `unmonitor ` + + > Asks me to stop monitoring changes on the webpage named <name>. + > > restricted to /AUTH + + `filter ` > Filters the display of tweets or news containing <word> or sent by user <@user>. @@ -178,9 +188,9 @@ > Removes a tweets display filter for <word> or <@user>. > > restricted to /AUTH - + `list [--chan ] ` + + `list [--chan ] ` - > Displays the list of filters or news or tweets queries followed for current channel or optional <channel>. + > Displays the list of filters or pages monitored or news or tweets queries followed for current channel or optional <channel>. + `newsurl ` diff --git a/gazouilleur/bot.py b/gazouilleur/bot.py index 62c4702..2267594 100644 --- a/gazouilleur/bot.py +++ b/gazouilleur/bot.py @@ -1046,11 +1046,11 @@ def command_stats(self, rest, channel=None, nick=None): return stats.print_last() - # Twitter & RSS Feeds monitoring commands - # --------------------------------------- - ## (Un)Follow and (Un)Filter available only to GLOBAL_USERS and chan's USERS + # Twitter, RSS Feeds & Webpages monitoring commands + # ------------------------------------------------- + ## (Un)Follow, (Un)Filter and Monitor available only to GLOBAL_USERS and chan's USERS ## Others available to anyone - ## Exclude regexp : '(u?n?f(ollow|ilter)|list|newsurl|last(tweet|news)|digest)' + ## Exclude regexp : '(u?n?f(ollow|ilter)|u?n?monitor|list|newsurl|last(tweet|news)|digest)' @inlineCallbacks def _restart_feeds(self, channel): @@ -1065,14 +1065,16 @@ def _restart_feeds(self, channel): re_url = re.compile(r'\s*(https?://\S+)\s*', re.I) @inlineCallbacks - def command_follow(self, query, channel=None, nick=None): + def command_follow(self, query, channel=None, nick=None, webpages=False): """follow : Asks me to follow and display elements from a RSS named at , or tweets matching or from <@user>./AUTH""" channel = self.getMasterChan(channel) url = self.re_url.search(query) if url and url.group(1): - database = 'news' + database = 'news' if not webpages else 'pages' name = remove_ext_quotes(query.replace(url.group(1), '').strip().lower()) query = url.group(1) + elif webpages: + returnD("Please specify a url for the page %s you want to monitor (%shelp monitor for more info)." % (query, COMMAND_CHAR_DEF)) else: database = 'tweets' name = 'TWEETS: %s' % query @@ -1080,25 +1082,25 @@ def command_follow(self, query, channel=None, nick=None): returnD("Please specify what you want to follow (%shelp follow for more info)." % COMMAND_CHAR_DEF) if len(query) > 300: returnD("Please limit your follow queries to a maximum of 300 characters") - if database == "news" and name == "": + if database != "tweets" and name == "": returnD("Please provide a name for this url feed.") yield self.db['feeds'].update({'database': database, 'channel': channel, 'name': name}, {'database': database, 'channel': channel, 'name': name, 'query': query, 'user': nick, 'timestamp': datetime.today()}, upsert=True) - if database == "news": - query = "%s <%s>" % (name, query) if database == "tweets": reactor.callLater(0.5, self._restart_feeds, channel) + else: + query = "%s <%s>" % (name, query) returnD('«%s» query added to %s database for %s' % (query, database, channel)) re_clean_query = re.compile(r'([()+|$])') regexp_feedquery = lambda self, x: re.compile(r'^%s$' % self.re_clean_query.sub(r'\\\1', x), re.I) @inlineCallbacks - def command_unfollow(self, query, channel=None, *args): + def command_unfollow(self, query, channel=None, nick=None, webpages=False): """unfollow : Asks me to stop following and displaying elements from a RSS named , or tweets matching or from <@user>./AUTH""" channel = self.getMasterChan(channel) query = query.strip("«»") - database = 'news' + database = 'news' if not webpages else 'pages' res = yield self.db['feeds'].remove({'channel': channel, 'name': self.regexp_feedquery(remove_ext_quotes(query)), 'database': database}, safe=True) - if not res or not res['n']: + if not ((res and res['n']) or webpages): database = 'tweets' res = yield self.db['feeds'].remove({'channel': channel, 'query': self.regexp_feedquery(query), 'database': database}, safe=True) if not res or not res['n']: @@ -1107,6 +1109,14 @@ def command_unfollow(self, query, channel=None, *args): reactor.callLater(0.5, self._restart_feeds, channel) returnD('«%s» query removed from %s database for %s' % (query, database, channel)) + def command_monitor(self, query, channel=None, nick=None): + """monitor : Asks me to regularily check and tell if the webpage at and identified as changes./AUTH""" + return self.command_follow(query, channel, nick, webpages=True) + + def command_unmonitor(self, query, channel=None, *args): + """unmonitor : Asks me to stop monitoring changes on the webpage named ./AUTH""" + return self.command_unfollow(query, channel, webpages=True) + @inlineCallbacks def command_filter(self, keyword, channel=None, nick=None): """filter : Filters the display of tweets or news containing or sent by user <@user>./AUTH""" @@ -1131,14 +1141,14 @@ def command_unfilter(self, keyword, channel=None, nick=None): @inlineCallbacks def command_list(self, database, channel=None, *args): - """list [--chan ] : Displays the list of filters or news or tweets queries followed for current channel or optional .""" + """list [--chan ] : Displays the list of filters or pages monitored or news or tweets queries followed for current channel or optional .""" try: database, channel = self._get_chan_from_command(database, channel) except Exception as e: returnD(str(e)) database = database.strip() - if database != "tweets" and database != "news" and database != "filters": - returnD('Please enter either «%slist tweets», «%slist news» or «%slist filters».' % (COMMAND_CHAR_DEF, COMMAND_CHAR_DEF, COMMAND_CHAR_DEF)) + if database not in ["tweets", "news", "filters", "pages"]: + returnD('Please enter either «%slist tweets», «%slist news», «%slist pages» or «%slist filters».' % (COMMAND_CHAR_DEF, COMMAND_CHAR_DEF, COMMAND_CHAR_DEF, COMMAND_CHAR_DEF)) if database == "filters": feeds = assembleResults(self.filters[channel.lower()]) else: diff --git a/gazouilleur/lib/mongo.py b/gazouilleur/lib/mongo.py index a2adcf6..d6a0fc1 100644 --- a/gazouilleur/lib/mongo.py +++ b/gazouilleur/lib/mongo.py @@ -59,6 +59,9 @@ def ensure_indexes(db): yield db['feeds'].ensure_index(sortasc('channel') + sortasc('database') + sortdesc('timestamp'), background=True) yield db['filters'].ensure_index(sortasc('channel'), background=True) yield db['filters'].ensure_index(sortasc('channel') + sortasc('keyword') + sortdesc('timestamp'), background=True) + yield db['pages'].ensure_index(sortdesc('_id') + sortasc('channel'), background=True) + yield db['pages'].ensure_index(sortasc('channel') + sortdesc('timestamp'), background=True) + yield db['pages'].ensure_index(sortasc('channel') + sortasc('source') + sortdesc('timestamp'), background=True) yield db['news'].ensure_index(sortdesc('_id') + sortasc('channel'), background=True) yield db['news'].ensure_index(sortasc('channel') + sortdesc('timestamp'), background=True) yield db['news'].ensure_index(sortasc('channel') + sortasc('source') + sortdesc('timestamp'), background=True)