// NewFromEnv checks config for the necessary tokens, returning an error // if there are any missing func NewFromEnv() (*API, error) { a := new(API) consumerKey, cKeyOk := config.Get("TWITTER_CONSUMER_KEY") consumerSecret, cSecOk := config.Get("TWITTER_CONSUMER_SECRET") accessToken, aTokOk := config.Get("TWITTER_ACCESS_TOKEN") accessSecret, aSecOk := config.Get("TWITTER_ACCESS_SECRET") if !cKeyOk || !cSecOk || !aTokOk || !aSecOk { return nil, ErrMissingTokens } anaconda.SetConsumerKey(consumerKey) anaconda.SetConsumerSecret(consumerSecret) a.api = anaconda.NewTwitterApi(accessToken, accessSecret) return a, nil }
func mehLookup(_ commands.Message, ret commands.MessageFunc) string { key, avail := config.Get("MEH_API") if !avail { return "" } client := meh.NewClient(meh.WithKey(key)) current, err := client.Current() if err != nil { return "Error contacting Meh API!" } title := current.Deal.Title price := current.Deal.Items[0].Price for i := 0; i < len(current.Deal.Items); i++ { if current.Deal.Items[i].Price != price { // At least one of the prices vary return fmt.Sprintf("Meh.com deal of the day: %s, varying prices", title) } } return fmt.Sprintf("Meh.com deal of the day: %s for $%d", title, price) }
func tumblrLookup(msg commands.Message, ret commands.MessageFunc) string { if len(msg.Params) < 2 { return "I need .tumblr [blog-url]" } blog := msg.Params[1] key, ok := config.Get("TUMBLR_API") if !ok { return "" } req := fmt.Sprintf("http://api.tumblr.com/v2/blog/%s/posts/text?api_key=%s", blog, key) data, err := util.Fetch(req) if err != nil { return "Unable to get data from tumblr" } var resp tumblrData if err := json.Unmarshal(data, &resp); err != nil { return "Tumblr gave me a bad response!" } if resp.Meta.Status != 200 { return "Tumblr returned an Error" } if len(resp.Response.Posts) < 1 { return "I didn't find any posts!" } post := resp.Response.Posts[0] return fmt.Sprintf("%s: %v @ %s", post.BlogName, post.Title, post.ShortURL) }
func fetchForecast(msg commands.Message, ret commands.MessageFunc) string { geoAddr, err := util.GetCoordinates(msg.Params[1:]) if err != nil { return "I couldn't track down that location!" } apikey, avail := config.Get("FORECASTIO_API") if avail != true { return "" } lat := strconv.FormatFloat(geoAddr.Lat, 'f', -1, 64) long := strconv.FormatFloat(geoAddr.Long, 'f', -1, 64) f, err := forecast.Get(apikey, lat, long, "now", forecast.US) if err != nil { return "Unable to fetch forecast!" } out := fmt.Sprintf("Forecast: %s", f.Daily.Summary) for i := 0; i < int(math.Min(float64(len(f.Daily.Data)), 3.0)); i++ { data := f.Daily.Data[i] out = fmt.Sprintf("%s | %s: %s [high: %.0fF, low: %.0fF]", out, time.Unix(int64(data.Time), 0).Format("Mon Jan 2"), data.Summary, data.TemperatureMax, data.TemperatureMin) if data.PrecipType != "" { out = fmt.Sprintf("%s; [%.0f%% of %s]", out, data.PrecipProbability*100.0, data.PrecipType) } } return out }
func convertCurrency(msg commands.Message, ret commands.MessageFunc) string { if len(msg.Params) < 5 { return "Usage: .convert [AMNT] [BASE CURRENCY] (in|to) [CONVERTED CURRENCY], ie: .convert 20 USD in GBP" } baseRate, err := strconv.ParseFloat(msg.Params[1], 64) if err != nil { return "I couldn't parse the base rate, type the command with no arguments for help" } data.Lock() defer data.Unlock() if time.Duration(time.Now().Sub(time.Unix(data.r.Timestamp, 0))) > 3*time.Hour { apikey, avail := config.Get("OPENEXCHANGE_API") if avail != true { return "" } if err := updateRates(apikey); err != nil { return "I was unable to update my exchange rates, apologies" } } fromCur, fromCurOk := data.r.Rates[strings.ToUpper(msg.Params[2])] toCur, toCurOk := data.r.Rates[strings.ToUpper(msg.Params[4])] if !toCurOk || !fromCurOk { return "I don't have the currencies you wanted listed." } convAmnt := baseRate * (toCur / fromCur) return fmt.Sprintf("%v %s = %.2f %s (%.4f %s per %s)", baseRate, msg.Params[2], convAmnt, msg.Params[4], (toCur / fromCur), msg.Params[4], msg.Params[2]) }
func weatherLookup(msg commands.Message, ret commands.MessageFunc) string { geoAddr, err := util.GetCoordinates(msg.Params[1:]) if err != nil { return "I couldn't track down that location!" } apiKey, avail := config.Get("WUNDERGROUND_API") if avail != true { return "" } url := fmt.Sprintf("http://api.wunderground.com/api/%s/conditions/q/%v,%v.json", apiKey, geoAddr.Lat, geoAddr.Long) data, err := util.Fetch(url) if err != nil { return "Unable to lookup weather" } var conditions weatherConditions if err := json.Unmarshal(data, &conditions); err != nil { return "Weather Underground gave me a bad response" } response := conditions.Current if response.Weather == "" { return "I couldn't find that location -- try again!" } location := fmt.Sprintf("%s (%s)", response.Location.Full, response.StationID) return fmt.Sprintf("%s is: %s - %s with %s humidity | Wind: %s | %s precip. today", location, response.Weather, response.TempString, response.RelHumidity, response.WindString, response.PrecipString) }
func walkscoreLookup(msg commands.Message, ret commands.MessageFunc) string { walkscore, avail := config.Get("WALKSCORE_API") if avail != true { return "" } geoAddr, err := util.GetCoordinates(msg.Params[1:]) if err != nil { return "Not found!" } lat := geoAddr.Lat long := geoAddr.Long addr := url.QueryEscape(geoAddr.FormattedAddress) walkscoreURL := fmt.Sprintf("http://api.walkscore.com/score?format=json&address=%v&lat=%v&lon=%v&wsapikey=%v", addr, lat, long, walkscore) wdata, err := util.Fetch(walkscoreURL) if err != nil { return "Error fetching walkscore data" } var ws walkScoreData if err := json.Unmarshal(wdata, &ws); err != nil { return "Walkscore gave me a bad response!" } if ws.Status != 1 { return "I couldn't find that in Walkscore's database" } return fmt.Sprintf("%s is a %s with a walkscore of %v", geoAddr.FormattedAddress, ws.Description, ws.Walkscore) }
func bingProcess(msg commands.Message, ret commands.MessageFunc, p bingProcesser) string { token, ok := config.Get("BING_API") if !ok { return "" } query := strings.Join(msg.Params[1:], " ") out, err := bingAPIFetch(query, token, p) if err != nil { return "Unable to execute that search, sorry!" } return out }
func getVideoInfo(id string) (*ytVideoResponse, bool) { key, avail := config.Get("GOOGLE_API") if !avail { return nil, false } videoURL := fmt.Sprintf("%svideos/?id=%s&key=%s&part=%s&fields=%s", baseURL, id, key, videoParts, videoFields) vData, err := util.Fetch(videoURL) if err != nil { return nil, false } var videoData tyVideo err = json.Unmarshal(vData, &videoData) if err != nil || len(videoData.Videos) < 1 { return nil, false } chanID := videoData.Videos[0].Snippet.ChannelID chanURL := fmt.Sprintf("%schannels/?id=%s&key=%s&part=%s&fields=%s", baseURL, chanID, key, chanParts, chanFields) cData, err := util.Fetch(chanURL) if err != nil { return nil, false } var chanData ytChannel err = json.Unmarshal(cData, &chanData) if err != nil || len(chanData.Channels) < 1 { return nil, false } title := videoData.Videos[0].Snippet.Title views, _ := strconv.ParseInt(videoData.Videos[0].Statistics.Views, 10, 64) uploadTime, _ := time.Parse(timeForm, videoData.Videos[0].Snippet.Published) dur, _ := duration.ParseString(videoData.Videos[0].ContentDetails.Duration) durTime := dur.ToDuration() channel := chanData.Channels[0].Snippet.Title response := &ytVideoResponse{ Title: title, Views: views, Duration: durTime, Channel: channel, UploadTime: uploadTime, } return response, true }
func (bingImageProcess) process(data []byte) (string, error) { var api imageResponse if err := json.Unmarshal(data, &api); err != nil { return "", err } if len(api.D.Results) == 0 { return "", errors.New("no results") } img := api.D.Results[0] client := new(http.Client) req, err := http.NewRequest("GET", img.MediaURL, nil) if err != nil { return "", err } resp, err := client.Do(req) if err != nil { return "", err } defer resp.Body.Close() name := uniuri.NewLen(10) extention, err := mime.ExtensionsByType(img.ContentType) if err != nil || len(extention) == 0 { name += ".png" // browser should pick up on it anyway } else { name += extention[0] } bucketName, bucketCfg := config.Get("BING_S3_BUCKET") awsRegion, regionCfg := config.Get("BING_S3_REGION") if !bucketCfg || !regionCfg { return "", errors.New("invalid bucket/region to upload") } url, err := util.UploadWithEnv(bucketName, awsRegion, name, img.ContentType, resp.Body) if err != nil { return "", err } return fmt.Sprintf("Image Result: %s", url), nil }
func defineWord(msg commands.Message, ret commands.MessageFunc) string { word := url.QueryEscape(strings.Join(msg.Params[1:], " ")) apiKey, avail := config.Get("WORDNIK_API") if avail != true { return "" } url := fmt.Sprintf("http://api.wordnik.com/v4/word.json/%s/definitions?includeRelated=false&api_key=%s&includeTags=false&limit=1&useCanonical=true", word, apiKey) data, err := util.Fetch(url) if err != nil { return "Unable to look up the definition of that word" } var response []defineReturn if err := json.Unmarshal(data, &response); err != nil { return "Wordnik gave me a bad answer for that word" } if len(response) > 0 { return fmt.Sprintf("%s (%s): %s", response[0].Word, response[0].PartOfSpeech, response[0].Text) } return "I couldn't find that word, sorry!" }
func gifMe(msg commands.Message, ret commands.MessageFunc) string { var opts []gifgo.OptFunc if key, ok := config.Get("GIPHY_KEY"); ok { opts = append(opts, gifgo.APIKey(key)) } client, err := gifgo.New(opts...) if err != nil { return "Unable to talk to Giphy" } var randQuery gifgo.RandomReq if len(msg.Params) > 1 { randQuery.Tag = strings.Join(msg.Params[1:], " ") } gif, err := client.Random(randQuery) if err != nil { return "Giphy returned an error" } return fmt.Sprintf("%s - Powered by GIPHY", gif.Data.ImageURL) }
func wolframLookup(msg commands.Message, ret commands.MessageFunc) string { appid, avail := config.Get("WOLFRAM_API") if avail != true { return "" } query := util.URLEncode(strings.Join(msg.Params[1:], " ")) getURL := fmt.Sprintf("%s?input=%s&appid=%s", geturl, query, appid) resp, err := util.Fetch(getURL) if err != nil { return "Wolfram returned an error!" } var d result if err := xml.Unmarshal(resp, &d); err != nil { fmt.Println(err) return "Wolfram did not return valid data!" } if len(d.Pods) < 2 && len(d.Pods[0].Subpods) > 0 && len(d.Pods[1].Subpods) > 0 { return "Wolfram did not return valid data!" } return fmt.Sprintf("wa: q: %s, a: %s", d.Pods[0].Subpods[0].Plaintext, removeNewLineUntil(d.Pods[1].Subpods[0].Plaintext, 200)) }