package main import ( "fmt" "io" "log" "net/http" "os" "strings" "time" "github.com/dghubble/go-twitter/twitter" "github.com/dghubble/oauth1" ) const AppName = "twimgarc" var appConfig *AppConfig func main() { var err error appConfig, err = NewAppConfig(os.Args) if err != nil { log.Fatal(err) } config := oauth1.NewConfig(appConfig.ApiToken, appConfig.ApiSecret) token := oauth1.NewToken(appConfig.AppToken, appConfig.AppSecret) httpClient := config.Client(oauth1.NoContext, token) sleepTime := time.Minute for { PrintIfVerbose(time.Now().Format("20060102T150405"), ": Start\n") err = ProcessTimeline(httpClient) if err != nil { // Backoff sleepTime = sleepTime * 2 } PrintIfVerbose(time.Now().Format("20060102T150405"), ": Done\n") time.Sleep(sleepTime) if appConfig.ForceDownload { PrintIfVerbose("'Force' flag set. Exiting.\n") break } } } // Doesn't work yet... func WatchStream(httpClient *http.Client) { // Twitter client client := twitter.NewClient(httpClient) params := &twitter.StreamUserParams{ With: "followings", StallWarnings: twitter.Bool(false), } stream, err := client.Streams.User(params) if err != nil { log.Fatal(err) } for message := range stream.Messages { fmt.Println(message) } fmt.Println("Message Channel Closed") } func ProcessTimeline(httpClient *http.Client) error { // Twitter client client := twitter.NewClient(httpClient) // Home Timeline (last 5 entries) tweets, _, err := client.Timelines.HomeTimeline(&twitter.HomeTimelineParams{Count: 5}) if err != nil { return err } for _, t := range tweets { for _, m := range t.Entities.Media { var filenamePts []string txtPts := strings.Fields(t.Text) var subFolder string for _, v := range txtPts { if strings.HasPrefix(v, "http") { break } if v[0] == '#' { if subFolder == "" { subFolder = v[1:] } } else { filenamePts = append(filenamePts, v) } } filename := strings.Join(filenamePts, "_") + ".jpg" create, err := t.CreatedAtTime() if err != nil { create = time.Now() } filename = subFolder + "/" + create.Format("20060102T150405") + "_" + filename if ImageNeedsDownload(filename) || appConfig.ForceDownload { err = DownloadImage(httpClient, m.MediaURLHttps, filename) if err != nil { PrintIfVerbose("Error downloading image (", m.MediaURLHttps, ")", err.Error(), "\n") } } } } return nil } func ImageNeedsDownload(filename string) bool { exist, err := FileExists(appConfig.GetFilePath(filename)) if err != nil { return false } return !exist } func DownloadImage(httpClient *http.Client, url, filename string) error { pts := strings.FieldsFunc(filename, func(c rune) bool { return c == '/' }) if len(pts) > 1 { err := CreateDirIfNotExist(appConfig.GetFilePath(pts[0])) if err != nil { fmt.Println(err.Error()) return err } } fmt.Println("Downloading ", url, " -> ", filename, "...") imgResp, err := httpClient.Get(url) if err != nil { PrintIfVerbose(err.Error(), "\n") return err } defer imgResp.Body.Close() file, err := os.Create(appConfig.GetFilePath(filename)) if err != nil { PrintIfVerbose(err.Error(), "\n") return err } defer file.Close() _, err = io.Copy(file, imgResp.Body) if err != nil { fmt.Println(err.Error(), "\n") } else { fmt.Println("Done\n") } return err } func PrintIfVerbose(val ...string) { if appConfig.Verbose { for _, v := range val { fmt.Print(v) } } } func PrintUsageAndExit() { fmt.Println(AppName + " - Download Images from a Twitter Stream") fmt.Println(" -count,-c= Pull the last tweets") fmt.Println(" -force,-f Download images even if the file already exists") fmt.Println(" -help ,-h View this message") fmt.Println(" -verbose ,-v Be chatty") fmt.Println() os.Exit(0) }