├── snapshot └── 1.png ├── .travis.yml ├── LICENSE ├── README.md └── main.go /snapshot/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kkdai/goInstagramDownloader/HEAD/snapshot/1.png -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - "1.11" 5 | - tip 6 | 7 | before_install: 8 | 9 | env: 10 | - GO111MODULE=on 11 | 12 | script: 13 | - go vet ./... -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Evan Lin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | goInstagram 2 | ====================== 3 | [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/kkdai/goInstagram/master/LICENSE) [![GoDoc](https://godoc.org/github.com/kkdai/goInstagram?status.svg)](https://godoc.org/github.com/kkdai/youtube) [![Build Status](https://travis-ci.org/kkdai/goInstagram.svg?branch=master)](https://travis-ci.org/kkdai/goInstagram) [![](https://goreportcard.com/badge/github.com/kkdai/goInstagram)](https://goreportcard.com/badge/github.com/kkdai/goInstagram) 4 | 5 | A Instagram photo tool that supports concurrency download. This tool help you to download those photos for your backup, all the photos still own by original creator. 6 | 7 | Install 8 | -------------- 9 | 10 | go get -u -x github.com/kkdai/goInstagramDownloader 11 | 12 | Note, you need go to [Instagram developer page](https://instagram.com/developer/clients/manage/) to get latest token and update in environment variables 13 | 14 | export InstagramID="YOUR_ClientID_HERE" 15 | 16 | Usage 17 | --------------------- 18 | 19 | goInstagramDownloader [options] 20 | 21 | All the photos will download to `USERS/Pictures/goInstagram`. 22 | 23 | Options 24 | --------------- 25 | 26 | - `-n` Instagram page name such as: [kingjames](https://instagram.com/kingjames/) 27 | - `-c` number of workers. (concurrency), default workers is "2" 28 | 29 | 30 | Examples 31 | --------------- 32 | 33 | Download all photos from LeBron James Instagram Photos with 10 workers. 34 | 35 | goInstagramDownloader -n=kingjames -c=10 36 | 37 | 38 | Snapshot 39 | --------------- 40 | 41 | ![image](snapshot/1.png) 42 | 43 | TODOs 44 | --------------- 45 | 46 | - Support video download. 47 | 48 | Inspired 49 | --------------- 50 | 51 | - Instagram API by Go [https://github.com/gedex/go-instagram](https://github.com/gedex/go-instagram). 52 | - Instagram Photo download by Python: [https://github.com/dangoldin/instagram-download](https://github.com/dangoldin/instagram-download) 53 | 54 | 55 | Contribute 56 | --------------- 57 | 58 | Please open up an issue on GitHub before you put a lot efforts on pull request. 59 | The code submitting to PR must be filtered with `gofmt` 60 | 61 | Related Project 62 | --------------- 63 | 64 | Here also a Facebook Photo downloader written by Go. [https://github.com/kkdai/goFBPages](https://github.com/kkdai/goFBPages) 65 | 66 | Advertising 67 | --------------- 68 | 69 | If you want to browse facebook page on your iPhone, why not check my App here :p [粉絲相簿](https://itunes.apple.com/tw/app/fen-si-xiang-bu/id839324997?l=zh&mt=8) 70 | 71 | Project52 72 | --------------- 73 | 74 | It is one of my [project 52](https://github.com/kkdai/project52). 75 | 76 | 77 | License 78 | --------------- 79 | 80 | This package is licensed under MIT license. See LICENSE for details. 81 | 82 | 83 | [![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/kkdai/goinstagramdownloader/trend.png)](https://bitdeli.com/free "Bitdeli Badge") 84 | 85 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "image" 7 | "image/jpeg" 8 | "image/png" 9 | "log" 10 | "net/http" 11 | "os" 12 | "os/user" 13 | "strings" 14 | "sync" 15 | 16 | "github.com/gedex/go-instagram/instagram" 17 | ) 18 | 19 | var instaName = flag.String("n", "", "Instangram user name such as: 'kingjames'") 20 | var numOfWorkersPtr = flag.Int("c", 2, "the number of concurrent rename workers. default = 2") 21 | 22 | var m sync.Mutex 23 | var FileIndex int = 0 24 | var client *instagram.Client 25 | 26 | func GetFileIndex() (ret int) { 27 | m.Lock() 28 | ret = FileIndex 29 | FileIndex = FileIndex + 1 30 | m.Unlock() 31 | return ret 32 | } 33 | 34 | var ClientID string 35 | 36 | func init() { 37 | ClientID = os.Getenv("InstagramID") 38 | if ClientID == "" { 39 | log.Fatalln("Please set 'export InstagramID=xxxxx' as your environment variables") 40 | 41 | } 42 | } 43 | 44 | func DownloadWorker(destDir string, linkChan chan string, wg *sync.WaitGroup) { 45 | defer wg.Done() 46 | 47 | for target := range linkChan { 48 | var imageType string 49 | if strings.Contains(target, ".png") { 50 | imageType = ".png" 51 | } else { 52 | imageType = ".jpg" 53 | } 54 | 55 | resp, err := http.Get(target) 56 | if err != nil { 57 | log.Println("Http.Get\nerror: " + err.Error() + "\ntarget: " + target) 58 | continue 59 | } 60 | defer resp.Body.Close() 61 | 62 | m, _, err := image.Decode(resp.Body) 63 | if err != nil { 64 | log.Println("image.Decode\nerror: " + err.Error() + "\ntarget: " + target) 65 | continue 66 | } 67 | 68 | // Ignore small images 69 | bounds := m.Bounds() 70 | if bounds.Size().X > 300 && bounds.Size().Y > 300 { 71 | imgInfo := fmt.Sprintf("pic%04d", GetFileIndex()) 72 | out, err := os.Create(destDir + "/" + imgInfo + imageType) 73 | if err != nil { 74 | log.Printf("os.Create\nerror: %s", err) 75 | continue 76 | } 77 | defer out.Close() 78 | if imageType == ".png" { 79 | png.Encode(out, m) 80 | } else { 81 | jpeg.Encode(out, m, nil) 82 | } 83 | 84 | if FileIndex%30 == 0 { 85 | fmt.Println(FileIndex, " photos downloaded.") 86 | } 87 | } 88 | } 89 | } 90 | 91 | func FindPhotos(ownerName string, albumName string, userId string, baseDir string) { 92 | totalPhotoNumber := 1 93 | var mediaList []instagram.Media 94 | var next *instagram.ResponsePagination 95 | var optParam *instagram.Parameters 96 | var err error 97 | 98 | //Create folder 99 | dir := fmt.Sprintf("%v/%v", baseDir, ownerName) 100 | os.MkdirAll(dir, 0755) 101 | linkChan := make(chan string) 102 | //Create download worker 103 | wg := new(sync.WaitGroup) 104 | for i := 0; i < 1; i++ { 105 | wg.Add(1) 106 | go DownloadWorker(dir, linkChan, wg) 107 | } 108 | 109 | for true { 110 | maxId := "" 111 | if next != nil { 112 | maxId = next.NextMaxID 113 | } 114 | 115 | optParam = &instagram.Parameters{Count: 10, MaxID: maxId} 116 | mediaList, next, err = client.Users.RecentMedia(userId, optParam) 117 | if err != nil { 118 | log.Println("err:", err) 119 | break 120 | } 121 | 122 | for _, media := range mediaList { 123 | totalPhotoNumber = totalPhotoNumber + 1 124 | linkChan <- media.Images.StandardResolution.URL 125 | } 126 | 127 | if len(mediaList) == 0 || next.NextMaxID == "" { 128 | break 129 | } 130 | } 131 | } 132 | 133 | func main() { 134 | flag.Parse() 135 | var inputUser string 136 | if *instaName == "" { 137 | log.Fatalln("You need to input -n=Name.") 138 | } 139 | inputUser = *instaName 140 | 141 | //Get system user folder 142 | usr, _ := user.Current() 143 | baseDir := fmt.Sprintf("%v/Pictures/goInstagram", usr.HomeDir) 144 | 145 | //Get User info 146 | client = instagram.NewClient(nil) 147 | client.ClientID = ClientID 148 | 149 | var userId string 150 | searchUsers, _, err := client.Users.Search(inputUser, nil) 151 | for _, user := range searchUsers { 152 | if user.Username == inputUser { 153 | userId = user.ID 154 | } 155 | } 156 | 157 | if userId == "" { 158 | log.Fatalln("Can not address user name: ", inputUser, err) 159 | } 160 | 161 | userFolderName := fmt.Sprintf("[%s]%s", userId, inputUser) 162 | fmt.Println("Starting download [", userId, "]", inputUser) 163 | FindPhotos(userFolderName, inputUser, userId, baseDir) 164 | } 165 | --------------------------------------------------------------------------------