Pārlūkot izejas kodu

feat: twitter scraper can use account login via "credentials" -> "twitterUsername" & "twitterPassword"

Drn 2 gadi atpakaļ
vecāks
revīzija
094708da1c
3 mainītis faili ar 51 papildinājumiem un 10 dzēšanām
  1. 3 5
      README.md
  2. 8 0
      config.go
  3. 40 5
      main.go

+ 3 - 5
README.md

@@ -102,7 +102,7 @@ Now that that's out of the way...
 
 - Direct Links to Files
 - Discord File Attachments
-- Twitter _(requires API key, see config section)_
+- Twitter _(requires account login, see config section)_
 - Instagram _(requires account login, see config section)_
 - Reddit
 - Imgur
@@ -271,10 +271,8 @@ The bot accepts `.json` or `.jsonc` for comment-friendly json.
         "token": "YOUR_USER_OR_BOT_TOKEN",        // user with 2FA or genuine Discord bot.
         "email": "YOUR_USER_EMAIL_NO_2FA",        // user without 2FA.
         "password": "YOUR_USER_PASSWORD_NO_2FA",  // user without 2FA.
-        "twitterAccessToken": "",       // Twitter v1.1 API.
-        "twitterAccessTokenSecret": "", // Twitter v1.1 API.
-        "twitterConsumerKey": "",       // Twitter v1.1 API.
-        "twitterConsumerSecret": "",    // Twitter v1.1 API.
+        "twitterUsername": "", // Twitter Account, not required but can be used for scraping private accounts.
+        "twitterPassword": "", // Twitter Account, not required but can be used for scraping private accounts.
         "instagramUsername": "", // Instagram Account, captcha required at some point(s).
         "instagramPassword": "", // Instagram Account, captcha required at some point(s).
         "flickrApiKey": ""

+ 8 - 0
config.go

@@ -32,6 +32,8 @@ type configurationCredentials struct {
 	Email    string `json:"email,omitempty"`    // required for login (this or token)
 	Password string `json:"password,omitempty"` // required for login (this or token)
 	// APIs
+	TwitterUsername   string `json:"twitterUsername,omitempty"`   // optional
+	TwitterPassword   string `json:"twitterPassword,omitempty"`   // optional
 	InstagramUsername string `json:"instagramUsername,omitempty"` // optional
 	InstagramPassword string `json:"instagramPassword,omitempty"` // optional
 	FlickrApiKey      string `json:"flickrApiKey,omitempty"`      // optional
@@ -557,6 +559,12 @@ func loadConfig() error {
 			if dupeConfig.Credentials.Password != "" && dupeConfig.Credentials.Password != placeholderPassword {
 				dupeConfig.Credentials.Password = "STRIPPED_FOR_OUTPUT"
 			}
+			if dupeConfig.Credentials.TwitterUsername != "" {
+				dupeConfig.Credentials.TwitterUsername = "STRIPPED_FOR_OUTPUT"
+			}
+			if dupeConfig.Credentials.TwitterPassword != "" {
+				dupeConfig.Credentials.TwitterPassword = "STRIPPED_FOR_OUTPUT"
+			}
 			if dupeConfig.Credentials.InstagramUsername != "" {
 				dupeConfig.Credentials.InstagramUsername = "STRIPPED_FOR_OUTPUT"
 			}

+ 40 - 5
main.go

@@ -42,6 +42,7 @@ var (
 	duploCatalog *duplo.Store
 
 	// APIs
+	twitterLoggedIn    bool = false
 	twitterScraper     *twitterscraper.Scraper
 	instagramConnected bool = false
 	instagramClient    *goinsta.Instagram
@@ -459,6 +460,10 @@ func main() {
 
 	sendStatusMessage(sendStatusExit) // not goroutine because we want to wait to send this before logout
 
+	if twitterScraper.IsLoggedIn() {
+		twitterScraper.Logout()
+	}
+
 	log.Println(lg("Discord", "", color.GreenString, "Logging out of discord..."))
 	bot.Close()
 
@@ -533,8 +538,38 @@ func botLoad() {
 
 func botLoadAPIs() {
 	// Twitter API
-	twitterScraper = twitterscraper.New()
-	//TODO: Optional Username+Password Auth
+	go func() {
+		twitterScraper = twitterscraper.New()
+		if config.Credentials.TwitterUsername != "" &&
+			config.Credentials.TwitterPassword != "" {
+			log.Println(lg("API", "Instagram", color.MagentaString, "Connecting to API..."))
+
+			twitterLoginCount := 0
+		do_twitter_login:
+			twitterLoginCount++
+			if twitterLoginCount > 1 {
+				time.Sleep(3 * time.Second)
+			}
+
+			if err := twitterScraper.Login(config.Credentials.TwitterUsername, config.Credentials.TwitterPassword); err != nil {
+				log.Println(lg("API", "Twitter", color.HiRedString, "Login Error: %s", err.Error()))
+				if twitterLoginCount <= 3 {
+					goto do_twitter_login
+				} else {
+					log.Println(lg("API", "Twitter", color.HiRedString,
+						"Failed to login to Twitter, the bot will not fetch media..."))
+				}
+			} else {
+				log.Println(lg("API", "Twitter", color.HiMagentaString, "Connected"))
+				if twitterScraper.IsLoggedIn() {
+					twitterLoggedIn = true
+				}
+			}
+		} else {
+			log.Println(lg("API", "Twitter", color.MagentaString,
+				"Twitter login missing, the bot won't use the Twitter library."))
+		}
+	}()
 
 	// Instagram API
 	go func() {
@@ -552,12 +587,12 @@ func botLoadAPIs() {
 			if instagramClient, err = goinsta.Import(instagramCachePath); err != nil {
 				instagramClient = goinsta.New(config.Credentials.InstagramUsername, config.Credentials.InstagramPassword)
 				if err := instagramClient.Login(); err != nil {
-					log.Println(lg("API", "Instagram", color.HiRedString, "API Login Error: %s", err.Error()))
+					log.Println(lg("API", "Instagram", color.HiRedString, "Login Error: %s", err.Error()))
 					if instagramLoginCount <= 3 {
 						goto do_instagram_login
 					} else {
 						log.Println(lg("API", "Instagram", color.HiRedString,
-							"Failed to login to Instagram API, the bot will not fetch instagram media..."))
+							"Failed to login to Instagram, the bot will not fetch media..."))
 					}
 				} else {
 					log.Println(lg("API", "Instagram", color.HiMagentaString,
@@ -572,7 +607,7 @@ func botLoadAPIs() {
 			}
 		} else {
 			log.Println(lg("API", "Instagram", color.MagentaString,
-				"API credentials missing, the bot won't use the Instagram API."))
+				"Instagram login missing, the bot won't use the Instagram library."))
 		}
 	}()