package main
import (
"database/sql"
"flag"
"github.com/ahmdrz/goinsta"
"github.com/ahmdrz/goinsta/response"
_ "github.com/lib/pq"
"log"
"os"
"regexp"
"strings"
"sync"
"time"
)
var (
username string
password string
email string
sleep int64
add bool
show bool
remove bool
connStr string = "user=postgres dbname=db_instagram sslmode=disable password=ccocot123"
)
func panicOnError(err error) {
if err != nil {
log.Panic(err)
}
}
func addAccount(db *sql.DB) {
isUsernameEmpty := !(len(username) > 0)
isPasswordEmpty := !(len(password) > 0)
isEmailEmpty := !(len(email) > 0)
if isUsernameEmpty || isPasswordEmpty || isEmailEmpty {
log.Panic("Username, Password or Email Empty\n")
}
insta := goinsta.New(username, password)
log.Print("Login Instagram ...\n")
err := insta.Login()
defer insta.Logout()
panicOnError(err)
_, err = db.Exec(`INSERT INTO account_info VALUES($1, $2, $3)`, username, password, email)
panicOnError(err)
log.Printf("User Added ! \n")
}
func showAccount(db *sql.DB) {
rows, err := db.Query(`SELECT username,password FROM account_info`)
panicOnError(err)
index := 0
for rows.Next() {
index++
var usernameTmp string
var passwordTmp string
err := rows.Scan(&usernameTmp, &passwordTmp)
panicOnError(err)
log.Printf("%d. Username: %s Password: %s \n", index, usernameTmp, passwordTmp)
}
}
func deleteAccount(db *sql.DB) {
isUsernameEmpty := !(len(username) > 0)
if isUsernameEmpty {
log.Panic("Username to delete Empty\n")
}
_, err := db.Exec(`DELETE FROM account_info WHERE username = $1`, username)
panicOnError(err)
log.Printf("User Deleted !\n")
}
func init() {
// flag
flag.StringVar(&username, "username", "", "instagram account username")
flag.StringVar(&password, "password", "", "instagram account password")
flag.StringVar(&email, "email", "", "instagram account email")
flag.Int64Var(&sleep, "sleep", 2, "sleep in minute")
flag.BoolVar(&add, "add", false, "add account instagram")
flag.BoolVar(&show, "show", false, "to show instagram account list")
flag.BoolVar(&remove, "remove", false, "remove instagram account")
flag.Parse()
//db connection
db, err := sql.Open("postgres", connStr)
panicOnError(err)
defer db.Close()
switch {
case add: //if flag add true
addAccount(db)
os.Exit(0)
case show: // if flag show true
showAccount(db)
os.Exit(0)
case remove: //if flag remove true
deleteAccount(db)
os.Exit(0)
}
}
func main() {
//db connection
db, err := sql.Open("postgres", connStr)
panicOnError(err)
defer db.Close()
// get account
rows, err := db.Query(`SELECT username, password FROM account_info`)
panicOnError(err)
accounts := [][]string{}
for rows.Next() {
var usernameTmp string
var passwordTmp string
rows.Scan(&usernameTmp, &passwordTmp)
itemToAppend := [][]string{{usernameTmp, passwordTmp}}
accounts = append(accounts, itemToAppend...)
}
log.Printf("Get All Worker [Total: %d account] \n", len(accounts))
// setup channel and waitgroup and worker login
var wg sync.WaitGroup
ch := make(chan *goinsta.Instagram, len(accounts))
for _, account := range accounts {
wg.Add(1)
go login(&wg, account, ch)
}
wg.Wait()
close(ch)
log.Printf("All worker Logged In, close channel and start to Work !!!\n")
//getTimeLine
for account := range ch {
wg.Add(1)
go getTimeLine(&wg, account, db)
}
wg.Wait()
log.Printf("All done")
}
func login(wg *sync.WaitGroup, account []string, ch chan *goinsta.Instagram) {
defer wg.Done()
log.Printf("worker %s try Login ... \n", account[0])
insta := goinsta.New(account[0], account[1])
err := insta.Login()
panicOnError(err)
log.Printf("worker %s Login Success ... \n", account[0])
ch <- insta
}
func getTimeLine(wg *sync.WaitGroup, account *goinsta.Instagram, db *sql.DB) {
defer wg.Done()
accountInfo, err := account.GetProfileData()
worker := accountInfo.User.Username
panicOnError(err)
maxID := ""
for {
feed, err := account.Timeline(maxID)
feed.AutoLoadMore = true
panicOnError(err)
for index, item := range feed.Items {
if mod := index % 3; index > 0 && mod == 0 {
time.Sleep(time.Duration(sleep) * time.Minute)
}
re := regexp.MustCompile(`(\#[a-zA-Z]+\b)`)
match := re.FindAllString(item.Caption.Text, -1)
result := doLike(account, &item, worker)
_, err := db.Exec(`INSERT INTO event VALUES(NOW(), $1, $2, $3, $4, $5);`,
worker,
result,
strings.Join(match, " "),
item.User.Username,
item.ID)
panicOnError(err)
}
if feed.MoreAvailable {
maxID = feed.NextMaxID
} else {
break
}
}
}
func doLike(insta *goinsta.Instagram, item *response.MediaItemResponse, worker string) bool {
liked := true
if !item.HasLiked {
_, err := insta.Like(item.ID)
if err != nil {
liked = false
}
}
log.Printf("[%s] %s => %s [%t]", worker, item.User.Username, item.ID, liked)
return liked
}
Comments