Skip to content

Commit

Permalink
Support download GIF
Browse files Browse the repository at this point in the history
  • Loading branch information
KazuProg committed May 3, 2024
1 parent 7de5459 commit f68243e
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 12 deletions.
13 changes: 8 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ Usage:
-t, --tweet TWEET_ID Single tweet id to download
-n, --nbr NBR Number of tweets to download
-i, --img Download images only
-g, --gif Download gifs only (need ffmpeg)
-v, --video Download videos only
-a, --all Download images and videos
-a, --all Download images, gifs(need ffmpeg) and videos
-r, --retweet Download retweet too
-z, --url Print media url without download it
-R, --retweet-only Donwload only retweet
Expand All @@ -38,7 +39,7 @@ Usage:

#### Download 300 tweets from @Spraytrains.

If the tweet doesn't contain a photo or video nothing will be downloaded but it will count towards the 300.
If the tweet doesn't contain a photo, gif or video nothing will be downloaded but it will count towards the 300.

```sh
twmd -u Spraytrains -o ~/Downloads -a -n 300
Expand All @@ -57,6 +58,11 @@ You can use `-r|--retweet` to download retweets as well, or `-R|--retweet-only`
twmd -t 156170319961391104
```

#### Download animated-GIFs:

Animated-GIFs are downloaded as mp4 files.
If you want to get them as gif files, you need to install ffmpeg.

#### NSFW tweets

You'll need to login `-L|--login` for downloading nsfw tweets.
Expand Down Expand Up @@ -134,6 +140,3 @@ fi


Check [here](https://gist.github.com/mmpx12/f0741d40909ed3f182fd6f9b33b580d7) for a full termux-url-opener example.


#### Gifs are not supported at the moment.
100 changes: 93 additions & 7 deletions twmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"net/http"
URL "net/url"
"os"
"os/exec"
"regexp"
"strconv"
"strings"
Expand All @@ -32,6 +33,7 @@ var (
onlyrtw bool
vidz bool
imgs bool
gifs bool
urlOnly bool
version = "1.13.2"
scraper *twitterscraper.Scraper
Expand Down Expand Up @@ -75,6 +77,7 @@ func download(wg *sync.WaitGroup, tweet interface{}, url string, filetype string
}

var f *os.File
var outputDir string
defer f.Close()
if dwn_type == "user" {
if update {
Expand All @@ -84,11 +87,16 @@ func download(wg *sync.WaitGroup, tweet interface{}, url string, filetype string
}
}
if filetype == "rtimg" {
f, _ = os.Create(output + "/img/RE-" + name)
outputDir = output + "/img/"
name = "RE-" + name
} else if filetype == "rtgif" {
outputDir = output + "/gif/"
name = "RE-" + name
} else if filetype == "rtvideo" {
f, _ = os.Create(output + "/video/RE-" + name)
outputDir = output + "/video/"
name = "RE-" + name
} else {
f, _ = os.Create(output + "/" + filetype + "/" + name)
outputDir = output + "/" + filetype + "/"
}
} else {
if update {
Expand All @@ -97,10 +105,39 @@ func download(wg *sync.WaitGroup, tweet interface{}, url string, filetype string
return
}
}
f, _ = os.Create(output + "/" + name)
outputDir = output + "/"
}

f, _ = os.Create(outputDir + name)
io.Copy(f, resp.Body)
fmt.Println("Downloaded " + name)

isGif := strings.Contains(url, "tweet_video")
if isGif {
_, err := exec.LookPath("ffmpeg")
if err != nil {
fmt.Println("Convert error: ", err)
return
}
gifName := strings.TrimSuffix(name, ".mp4") + ".gif"

args := []string{
"-y",
"-i", outputDir + name,
"-c:v", "gif",
outputDir + gifName,
}

cmd := exec.Command("ffmpeg", args...)
err = cmd.Run()
if err != nil {
fmt.Println("Convert error: ", err)
return
}

os.Remove(outputDir + name)
fmt.Println("Converted " + gifName)
}
}

func vidUrl(video string) string {
Expand Down Expand Up @@ -162,6 +199,24 @@ func photoUser(wait *sync.WaitGroup, tweet *twitterscraper.TweetResult, output s
}
}

func gifUser(wait *sync.WaitGroup, tweet *twitterscraper.TweetResult, output string, rt bool) {
defer wait.Done()
wg := sync.WaitGroup{}
if len(tweet.GIFs) > 0 || tweet.IsRetweet {
if tweet.IsRetweet && (rt || onlyrtw) {
singleTweet(output, tweet.ID)
}
for _, i := range tweet.GIFs {
if onlyrtw || tweet.IsRetweet {
continue
}
wg.Add(1)
go download(&wg, tweet, i.URL, "gif", output, "user")
}
wg.Wait()
}
}

func videoSingle(tweet *twitterscraper.Tweet, output string) {
if tweet == nil {
return
Expand Down Expand Up @@ -190,7 +245,6 @@ func photoSingle(tweet *twitterscraper.Tweet, output string) {
if len(tweet.Photos) > 0 {
wg := sync.WaitGroup{}
for _, i := range tweet.Photos {
fmt.Println(i.URL)
var url string
if !strings.Contains(i.URL, "video_thumb/") {
if size == "orig" || size == "small" {
Expand All @@ -211,6 +265,25 @@ func photoSingle(tweet *twitterscraper.Tweet, output string) {
}
}

func gifSingle(tweet *twitterscraper.Tweet, output string) {
if tweet == nil {
return
}
if len(tweet.GIFs) > 0 {
wg := sync.WaitGroup{}
for _, i := range tweet.GIFs {
if usr != "" {
wg.Add(1)
go download(&wg, tweet, i.URL, "rtgif", output, "user")
} else {
wg.Add(1)
go download(&wg, tweet, i.URL, "tweet", output, "tweet")
}
}
wg.Wait()
}
}

func askPass(loginp, twofa bool) {
for {
var username string
Expand Down Expand Up @@ -280,9 +353,13 @@ func singleTweet(output string, id string) {
if imgs {
photoSingle(tweet, output)
}
if gifs {
gifSingle(tweet, output)
}
} else {
videoSingle(tweet, output)
photoSingle(tweet, output)
gifSingle(tweet, output)
}
}

Expand Down Expand Up @@ -418,6 +495,7 @@ func main() {
op.On("-t", "--tweet TWEET_ID", "Single tweet to download", &single)
op.On("-n", "--nbr NBR", "Number of tweets to download", &nbr)
op.On("-i", "--img", "Download images only", &imgs)
op.On("-g", "--gif", "Download GIFs only", &gifs)
op.On("-v", "--video", "Download videos only", &vidz)
op.On("-a", "--all", "Download images and videos", &all)
op.On("-r", "--retweet", "Download retweet too", &retweet)
Expand Down Expand Up @@ -456,9 +534,10 @@ func main() {
if all {
vidz = true
imgs = true
gifs = true
}
if !vidz && !imgs && single == "" {
fmt.Println("You must specify what to download. (-i --img) for images, (-v --video) for videos or (-a --all) for both")
if !vidz && !imgs && !gifs && single == "" {
fmt.Println("You must specify what to download. (-i --img) for images, (-g --gif) for gifs, (-v --video) for videos or (-a --all) for both")
op.Help()
os.Exit(1)
}
Expand Down Expand Up @@ -527,6 +606,9 @@ func main() {
if imgs {
os.MkdirAll(output+"/img", os.ModePerm)
}
if gifs {
os.MkdirAll(output+"/gif", os.ModePerm)
}
nbrs, _ := strconv.Atoi(nbr)
wg := sync.WaitGroup{}
for tweet := range scraper.GetTweets(context.Background(), usr, nbrs) {
Expand All @@ -542,6 +624,10 @@ func main() {
wg.Add(1)
go photoUser(&wg, tweet, output, retweet)
}
if gifs {
wg.Add(1)
go gifUser(&wg, tweet, output, retweet)
}
}
wg.Wait()
}

0 comments on commit f68243e

Please sign in to comment.