Skip to content

Commit

Permalink
Fixed login issue
Browse files Browse the repository at this point in the history
  • Loading branch information
mmpx12 committed Feb 14, 2025
1 parent 1d4f869 commit 2a390d3
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 65 deletions.
36 changes: 20 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

This twitter downloader doesn't require Credentials or an api key. It's based on [twitter-scrapper](https://github.com/imperatrona/twitter-scraper).

Unfortunately, you will not be able to download more than 3200 tweets.
### Note
For NSFW or private accounts, you will need to logged in (-L). Username ans password login isn't supported anymore. You'll have to logged in in a browser and copy auth_token and ct0 cookies (right click => inspect => storage => cookies).
It will create a twmd_cookies.json so you will not have to enter these cookies everytime.


![gui](.github/screenshots/gui.png)
**Note:** Gui is not longer maintained.
Expand All @@ -12,28 +15,29 @@ Unfortunately, you will not be able to download more than 3200 tweets.
```
Usage:
-h, --help Show this help
-u, --user USERNAME User you want to download
-t, --tweet TWEET_ID Single tweet id to download
-n, --nbr NBR Number of tweets to download
-u, --user=USERNAME User you want to download
-t, --tweet=TWEET_ID Single tweet to download
-n, --nbr=NBR Number of tweets to download
-i, --img Download images only
-v, --video Download videos only
-a, --all Download images and videos
-r, --retweet Download retweet too
-z, --url Print media url without download it
-R, --retweet-only Donwload only retweet
-M, --mediatweet-only Donwload only media tweet
-s, --size SIZE Choose format between small|normal|large
(default large)
-R, --retweet-only Download only retweet
-M, --mediatweet-only Download only media tweet
-s, --size=SIZE Choose size between small|normal|large (default
large)
-U, --update Download missing tweet only
-L, --login Log in to your account
-P, --login-plaintext Plain text Login (needed for NSFW tweets)
-o, --output DIR Output directory
-f, --file-format FORMAT Formatted name for the downloaded file
-d, --date-format FORMAT Apply custom date format. (https://go.dev/src/time/format.go)
-p, --proxy PROXY Use proxy (proto://ip:port)
-V, --version Print version and exit
-B, --[no-]banner Don't print banner
-o, --output=DIR Output directory
-f, --file-format=FORMAT Formatted name for the downloaded file, {DATE}
{USERNAME} {NAME} {TITLE} {ID}
-d, --date-format=FORMAT Apply custom date format.
(https://go.dev/src/time/format.go)
-L, --login Login (needed for NSFW tweets)
-C, --cookies Use cookies for authentication
-p, --proxy=PROXY Use proxy (proto://ip:port)
-V, --version Print version and exit
-B, --no-banner Don't print banner
```

### Examples:
Expand Down
8 changes: 4 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
module twmd

go 1.23.3
go 1.23.4

require (
github.com/andlabs/ui v0.0.0-20200610043537-70a69d6ae31e
github.com/imperatrona/twitter-scraper v0.0.15
github.com/imperatrona/twitter-scraper v0.0.16
github.com/mmpx12/optionparser v1.1.0
github.com/n0madic/twitter-scraper v0.0.0-20231104223941-296710769dd8
github.com/sqweek/dialog v0.0.0-20240226140203-065105509627
golang.org/x/term v0.26.0
golang.org/x/term v0.29.0
)

require (
github.com/AlexEidt/Vidio v1.5.1 // indirect
github.com/TheTitanrain/w32 v0.0.0-20180517000239-4f5cfb03fabf // indirect
github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be // indirect
golang.org/x/net v0.29.0 // indirect
golang.org/x/sys v0.27.0 // indirect
golang.org/x/sys v0.30.0 // indirect
)
12 changes: 6 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be/go.mod
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/imperatrona/twitter-scraper v0.0.15 h1:8BcaDK+pD4pPNgcV2UloHgnaIt47wCQIsaIDeGnM6rI=
github.com/imperatrona/twitter-scraper v0.0.15/go.mod h1:38MY3g/h4V7Xl4HbW9lnkL8S3YiFZenBFv86hN57RG8=
github.com/imperatrona/twitter-scraper v0.0.16 h1:XrJZDGqr0/A7C3qRyoud9Ue9k6eUP10VkfRij3ewkSA=
github.com/imperatrona/twitter-scraper v0.0.16/go.mod h1:38MY3g/h4V7Xl4HbW9lnkL8S3YiFZenBFv86hN57RG8=
github.com/mmpx12/optionparser v1.1.0 h1:CgfC8WBDxkHOlg9myndDMezNiyXeMzVRDLWDRIjdlf8=
github.com/mmpx12/optionparser v1.1.0/go.mod h1:1Ub9+E2fDinPCmAU2lCuJcXE8x0HCmkurDv+lcXgRd8=
github.com/n0madic/twitter-scraper v0.0.0-20231104223941-296710769dd8 h1:yToM7p7HL/WwEESkupFV3Nf7a8d80CHaKRoFNstGA2U=
Expand Down Expand Up @@ -60,8 +60,8 @@ golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
Expand All @@ -72,8 +72,8 @@ golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8=
golang.org/x/term v0.26.0 h1:WEQa6V3Gja/BhNxg540hBip/kkaYtRg3cxg4oXSw4AU=
golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E=
golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU=
golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
Expand Down
66 changes: 27 additions & 39 deletions twmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import (

twitterscraper "github.com/imperatrona/twitter-scraper"
"github.com/mmpx12/optionparser"
"golang.org/x/term"
)

var (
Expand All @@ -34,7 +33,7 @@ var (
vidz bool
imgs bool
urlOnly bool
version = "1.13.7"
version = "1.14.0"
scraper *twitterscraper.Scraper
client *http.Client
size = "orig"
Expand Down Expand Up @@ -231,35 +230,25 @@ func processCookieString(cookieStr string) []*http.Cookie {
return cookies
}

func askPass(loginp, twofa bool) {
func askPass() {
for {
var username string
var pass string
fmt.Printf("username: ")
fmt.Scanln(&username)
fmt.Printf("password: ")
if loginp {
fmt.Scanln(&pass)
} else {
password, _ := term.ReadPassword(int(os.Stdin.Fd()))
fmt.Println()
pass = string(password)
}
if !twofa {
err := scraper.Login(username, pass)
if err != nil {
fmt.Println(err)
}
} else {
var code string
fmt.Printf("two-factor: ")
fmt.Scanln(&code)
fmt.Println()
scraper.Login(username, string(pass), code)
}
var auth_token, ct0 string
fmt.Println(` ╔═══════════════════════════════════════════════════════════════╗
║ ║
║ User/pass login is no longer supported, ║
║ Log in using a browser and find auth_token and ct0 cookies. ║
║ (via Inspect → Storage → Cookies). ║
║ ║
╚═══════════════════════════════════════════════════════════════╝`)
fmt.Println()
fmt.Printf("auth_token cookie: ")
fmt.Scanln(&auth_token)
fmt.Printf("ct0 cookie: ")
fmt.Scanln(&ct0)
scraper.SetAuthToken(twitterscraper.AuthToken{Token: auth_token, CSRFToken: ct0})
if !scraper.IsLoggedIn() {
fmt.Println("Bad user/pass")
continue
fmt.Println("Bad Cookies.")
askPass()
}
cookies := scraper.GetCookies()
js, _ := json.Marshal(cookies)
Expand All @@ -270,7 +259,7 @@ func askPass(loginp, twofa bool) {
}
}

func Login(loginp, twofa bool, useCookies bool) {
func Login(useCookies bool) {
if useCookies {
if _, err := os.Stat("twmd_cookies.json"); errors.Is(err, fs.ErrNotExist) {
fmt.Print("Enter cookies string: ")
Expand All @@ -291,10 +280,11 @@ func Login(loginp, twofa bool, useCookies bool) {
var cookies []*http.Cookie
json.NewDecoder(f).Decode(&cookies)
scraper.SetCookies(cookies)
fmt.Println(scraper.IsLoggedIn())
}
} else {
if _, err := os.Stat("twmd_cookies.json"); errors.Is(err, fs.ErrNotExist) {
askPass(loginp, twofa)
askPass()
} else {
f, _ := os.Open("twmd_cookies.json")
var cookies []*http.Cookie
Expand All @@ -307,12 +297,12 @@ func Login(loginp, twofa bool, useCookies bool) {
if useCookies {
fmt.Println("Invalid cookies. Please try again.")
os.Remove("twmd_cookies.json")
Login(loginp, twofa, useCookies)
Login(useCookies)
} else {
askPass(loginp, twofa)
askPass()
}
} else {
fmt.Println("Logged in")
fmt.Println("Logged in.")
}
}

Expand Down Expand Up @@ -463,7 +453,7 @@ func getFormat(tweet interface{}) string {

func main() {
var nbr, single, output string
var retweet, all, printversion, nologo, login, loginp, twofa, useCookies bool
var retweet, all, printversion, nologo, login, useCookies bool
op := optionparser.NewOptionParser()
op.Banner = "twmd: Apiless twitter media downloader\n\nUsage:"
op.On("-u", "--user USERNAME", "User you want to download", &usr)
Expand All @@ -482,8 +472,6 @@ func main() {
op.On("-f", "--file-format FORMAT", "Formatted name for the downloaded file, {DATE} {USERNAME} {NAME} {TITLE} {ID}", &format)
op.On("-d", "--date-format FORMAT", "Apply custom date format. (https://go.dev/src/time/format.go)", &datefmt)
op.On("-L", "--login", "Login (needed for NSFW tweets)", &login)
op.On("-P", "--login-plaintext", "Plain text login (needed for NSFW tweets)", &loginp)
op.On("-2", "--2fa", "Use 2fa", &twofa)
op.On("-C", "--cookies", "Use cookies for authentication", &useCookies)
op.On("-p", "--proxy PROXY", "Use proxy (proto://ip:port)", &proxy)
op.On("-V", "--version", "Print version and exit", &printversion)
Expand Down Expand Up @@ -556,8 +544,8 @@ func main() {
scraper.SetProxy(proxy)

// Modified login handling
if login || loginp || useCookies {
Login(loginp, twofa, useCookies)
if login || useCookies {
Login(useCookies)
}

if single != "" {
Expand Down

0 comments on commit 2a390d3

Please sign in to comment.