def execute(self, **kwargs): """Retrieve mail from a GMail account through curl.""" # Load command settings from a configuration file settings = ConfigParser.SafeConfigParser() settings.read(utils.get_plugin_settings_paths(__name__)) try: username = settings.get("Credentials", "username") password = settings.get("Credentials", "password") except ConfigParser.NoOptionError: raise plugin.UnsuccessfulExecution( "Error: username/password " "not provided in settings file.") cmd = ("curl -u {0}:{1} --silent \"https://mail.google.com/mail/" "feed/atom\" | tr -d '\n' | awk -F '<entry>' '{" "for (i=2; i<=NF; i++) {print $i}}' | " "sed -n \"s/<title>\\(.*\)<\\/title.*name>\\(.*\\)" "<\\/name>.*/\\2 - \\1/p\"".format(username, password)) proc = sp.Popen(cmd, stdout=sp.PIPE, stderr=sp.PIPE, shell=True) out, err = proc.communicate() if out == "": out = "No mail." if len(out) == 0: raise plugin.UnsuccessfulExecution(err) return out
def execute(self, **kwargs): """Search Google and return the first result. Keyword arguments: query -- the query to search for """ if "query" not in kwargs: raise plugin.UnsuccessfulExecution('Error: No search string.') query = urllib.urlencode({'q': kwargs["query"]}) url = ('http://ajax.googleapis.com/ajax/services/' 'search/web?v=1.0&' + query) search_results = urllib.urlopen(url) response = json.loads(search_results.read()) results = response['responseData']['results'] try: # Strips HTML formatting ret = re.sub(r'<[^>]*?>', '', results[0]['content']) except: raise plugin.UnsuccessfulExecution("There was an error parsing data. " "Please try again.") # Strips HTML special characters (ie. " ) ret = re.sub(r'&[^ ]*?;', '', ret) return unicodedata.normalize('NFKD', ret).encode('ascii', 'ignore')
def execute(self, **kwargs): """Download and start the provided media. Downloads the link with the highest seed count. Keyword arguments: file -- the .torrent file to find and download name -- either an IMDB link to the media or the media name to search for """ if not self.settings.has_option("Downloads", "download_dir"): raise plugin.UnsuccessfulExecution( "Could not continue - " "no download directory in settings.") if "file" in kwargs: tfile = kwargs["file"] movie_name = "torrent" elif "name" in kwargs: movie_name = kwargs["name"] if movie_name.startswith("http://www.imdb.com/"): try: response = urllib2.urlopen(movie_name) data = response.read() match = re.search("<title>(.*?)</title>", data) if match: title_extra = " - IMDb" movie_name = match.group(1) if movie_name.endswith(title_extra): movie_name = movie_name[0:len(movie_name) - len(title_extra)] else: return "Error finding IMDB movie title." except urllib2.URLError: return "Error loading IMDB link." tfile = self.search(movie_name) if not tfile: return "Could not find any torrents." else: raise plugin.UnsuccessfulExecution("No media name provided.") try: if self.begin_torrent(tfile): return "Now downloading {0}".format(movie_name) else: return "Torrent downloaded, but could not be started." except Exception as err: logger.log("Error starting torrent", err) raise plugin.UnsuccessfulExecution("Error starting torrent.")
def interpret(self, arg='', **kwargs): """Retrieve directions from Google Maps and format them in a human-readable manner. Keyword arguments: to -- the destination address from -- the source address (default: current location, if available) """ if "to" in kwargs: destination = kwargs["to"] else: destination = (yield "Please provide a destination.")["_raw"] origin = kwargs.get("from", '') if origin == '': try: origin = self.registrar.request_service( *self.registrar.find_best_service('location')) except Exception as error: logger.log("Could not determine location", error) # raise plugin.UnsuccessfulExecution("Could not determine location.") origin = (yield "Could not automatically determine your location. " "Where are you starting from?")["_raw"] params = { 'q': 'from:{0} to:{1}'.format(origin, destination), 'output': 'json', 'oe': 'utf8', } encoded_params = urllib.urlencode(params) url = 'http://maps.google.com/maps/nav?' + encoded_params request = urllib2.Request(url) resp = urllib2.urlopen(request) response = json.load(resp) status_code = response['Status']['code'] if status_code == 200: yield self.format_directions_for_human( response['Directions']['Routes'][0]['Steps']) return elif status_code == 602: raise plugin.UnsuccessfulExecution('malformed query') raise plugin.UnsuccessfulExecution("Unknown status code: " + status_code)
def execute(self, **kwargs): """Log into Google Latitude and retrieve the user's current location. Keyword arguments: noreverse -- Return the latitude and longitude pair rather than turn it into a human-readable location. (default False) """ settings = ConfigParser.SafeConfigParser() settings.read(utils.get_plugin_settings_paths(__name__)) try: auth = open(settings.get('Settings', 'AUTHPATH'), "r") credentials = pickle.loads(auth.read()) auth.close() except ConfigParser.NoSectionError: raise plugin.UnsuccessfulExecution("'Settings' section missing from " "config file.") except ConfigParser.NoOptionError: raise plugin.UnsuccessfulExecution("Server not authenticated " "with Google Latitude.") except IOError: raise plugin.UnsuccessfulExecution("Error opening authentication file.") http = httplib2.Http() http = credentials.authorize(http) lat = build("latitude", "v1", http=http) data = lat.currentLocation().get(granularity="best").execute() if all(k in data for k in ('latitude', 'longitude')): if kwargs.get("noreverse", False): return "({0}, {1})".format(data['latitude'], data['longitude']) else: ret = self.lookup(data['latitude'], data['longitude']) if ret == None: return "({0}, {1})".format(data['latitude'], data['longitude']) else: return ret else: if 'kind' in data: raise plugin.UnsuccessfulExecution("No latitude data available.") else: raise plugin.UnsuccessfulExecution("Error in Latitude response.")
def execute(self, **kwargs): """Schedule a command to be run at a later time. Keyword arguments: command -- the command (in natural language) to be run in -- a relative time offset (hours, minutes, and/or seconds) at -- an absolute time to run the command """ expire = 0 if "command" not in kwargs: raise plugin.UnsuccessfulExecution("No command provided.") if "in" in kwargs: try: idx = kwargs["in"].rfind(" ") wait = kwargs["in"][:idx] scale = kwargs["in"][idx + 1:] except ValueError: raise plugin.UnsuccessfulExecution("Error parsing time.") try: expire = int(wait) except ValueError: try: expire = utils.text_to_int(wait) except: raise plugin.UnsuccessfulExecution("Error parsing time.") if scale.startswith("h"): expire = datetime.datetime.now() + datetime.timedelta( hours=expire) elif scale.startswith("m"): expire = datetime.datetime.now() + datetime.timedelta( minutes=expire) elif scale.startswith("s"): expire = datetime.datetime.now() + datetime.timedelta( seconds=expire) else: raise plugin.UnsuccessfulExecution( "Could not determine time scale (h/m/s).") elif "at" in kwargs: expire = utils.text_to_absolute_time(wait) if not expire: raise plugin.UnsuccessfulExecution("Error parsing time.") else: raise plugin.UnsuccessfulExecution( 'Command could not be scheduled. Must specify "in" or "at"') cmd, namespace, args = self.registrar.find_best_service( kwargs["command"]) if cmd is None: raise plugin.UnsuccessfulExecution("Provided text could not be " "converted into a command.") self.queue.put((expire, (cmd, namespace, args))) self.event.set() return 'Command scheduled.'
def execute(self, **kwargs): """Insert memo text as a new line in the memo file. Keyword arguments: memo -- the text to insert into the memo file """ if "memo" in kwargs: try: with open(self.settings.get('Settings', 'memo_file'), "a") as fil: fil.write(kwargs["memo"] + "\n") return "Inserted into memo file." except IOError, err: logger.log("Error while writing to file", err) raise plugin.UnsuccessfulExecution( "Error while writing to file.")
def execute(self, **kwargs): """Retrieve the latest weather for the provided location for the given time. Keyword arguments: last -- if True, return the last retrieved weather data where -- the location to get weather data for (defaults to current location) Can be an alias (defined in the configuration file) when -- one of 'today' or 'tomorrow' (default 'today') """ if kwargs.get("last", None): if self.last: if time.time() < self.last[1].ttl: yield "Data for {0}: {1}".format(self.last[0], self.last[1].val) return else: self.last = None raise plugin.UnsuccessfulExecution("No recent data stored.") if "where" not in kwargs: try: # Try to call on latitude plugin to get the current location kwargs["where"] = re.sub( "[() ]", "", self.registrar.request_service('location', noreverse=True)) except: #raise plugin.UnsuccessfulExecution("No current location is available.") kwargs["where"] = (yield "I could not find your current location, " "where do you want weather for?")["_raw"] forecastday = 0 if "when" in kwargs: if kwargs["when"].upper() == "TODAY": forecastday = 0 if kwargs["when"].upper() == "TOMORROW": forecastday = 1 location = kwargs["where"] # Sub any aliases if location in self.locations: location = self.locations[location] # Look in the cache, pick item with minimum distance from location, then # check to see if it's within the tolerance if len(self.cache) > 0: cache_hit_distances = ((item, self.distance(location, item)) for item in self.cache) closest_hit = min(cache_hit_distances, key=lambda x: x[1])[0] if closest_hit < self.max_cache_distance: if time.time() < self.cache[location].expires: yield self.cache[location].val return else: self.cache.pop(location, None) url = "http://api.wunderground.com/api/{0}/forecast".format( self.api_key) query = "/q/{0}.json".format(re.sub('\s+', '_', location)) resp = json.load(urllib2.urlopen(urllib2.Request(url + query))) if not resp: raise plugin.UnsuccessfulExecution("Parsing failed for location " + location) ret = None if 'results' in resp['response']: results = resp['response']['results'] while len(results) > 1: ret = "Did you mean " states = set() countries = set() for result in results: if result['state'] != '': states.add(result['state'].lower()) elif result['country'] != '': countries.add(result['country'].lower()) if len(states) > 0: ret += "the state" if len(states) > 1: ret += "s" ret += ' ' + utils.humanize_join( abbrev.states.try_long(x).capitalize() for x in states) if len(countries) > 0: if len(states) > 0: ret += " or " ret += "the country" if len(countries) > 1: ret += "s" ret += ' ' + utils.humanize_join( abbrev.countries.try_long(x).capitalize() for x in countries) ret += "?" # TODO better parsing of conversation arguments cont = (yield ret)['_raw'].split() old_results = results results = [] for word in cont: # Try to convert long name to abbrev state = abbrev.states.try_short(word) country = abbrev.countries.try_short(word) for result in old_results: if result['state'].lower() == state.lower(): results.append(result) elif result['country'].lower() == country.lower(): results.append(result) if len(results) == 0: # Invalid input was given, back up results = old_results query = results[0]['l'] + '.json' resp = json.load(urllib2.urlopen(urllib2.Request(url + query))) if not resp: raise plugin.UnsuccessfulExecution( "Parsing failed for location " + location) try: forecast = resp['forecast']['txt_forecast']['forecastday'] ret = forecast[forecastday]['fcttext'] except KeyError as err: logger.log("Error parsing forecast:", err) if not ret: raise plugin.UnsuccessfulExecution( "There is no weather data for this location") self.last = (location, self.CacheItem(time.time() + self.ttl, ret)) self.cache[location] = self.last[1] yield ret
registrar.register_service("remember", self.execute, grammar={"memo": []}, usage=usage, namespace=__name__) def disable(self): """Disable all of Memo's services.""" self.registrar.unregister_service("memo", namespace=__name__) self.registrar.unregister_service("remember", namespace=__name__) def execute(self, **kwargs): """Insert memo text as a new line in the memo file. Keyword arguments: memo -- the text to insert into the memo file """ if "memo" in kwargs: try: with open(self.settings.get('Settings', 'memo_file'), "a") as fil: fil.write(kwargs["memo"] + "\n") return "Inserted into memo file." except IOError, err: logger.log("Error while writing to file", err) raise plugin.UnsuccessfulExecution( "Error while writing to file.") else: raise plugin.UnsuccessfulExecution("Must provide data to insert.")