SocialDragon/instagram/api.go

249 lines
7.2 KiB
Go

package instagram
import (
"crypto/sha256"
"encoding/hex"
"encoding/json"
"errors"
"io"
"io/ioutil"
"log"
"os"
"github.com/disintegration/imaging"
"git.1750studios.com/AniNite/SocialDragon/config"
)
// ListResponse defines the instagram list response
type ListResponse struct {
Tag struct {
Name string `json:"name"`
ContentAdvisory interface{} `json:"content_advisory"`
Media struct {
Nodes []struct {
CommentsDisabled bool `json:"comments_disabled"`
ID string `json:"id"`
Dimensions struct {
Height int `json:"height"`
Width int `json:"width"`
} `json:"dimensions"`
Owner struct {
ID string `json:"id"`
} `json:"owner"`
ThumbnailSrc string `json:"thumbnail_src"`
IsVideo bool `json:"is_video"`
Code string `json:"code"`
Date int `json:"date"`
DisplaySrc string `json:"display_src"`
Caption string `json:"caption"`
Comments struct {
Count int `json:"count"`
} `json:"comments"`
Likes struct {
Count int `json:"count"`
} `json:"likes"`
} `json:"nodes"`
Count int `json:"count"`
PageInfo struct {
HasNextPage bool `json:"has_next_page"`
EndCursor string `json:"end_cursor"`
} `json:"page_info"`
} `json:"media"`
TopPosts struct {
Nodes []struct {
ID string `json:"id"`
Dimensions struct {
Height int `json:"height"`
Width int `json:"width"`
} `json:"dimensions"`
Owner struct {
ID string `json:"id"`
} `json:"owner"`
ThumbnailSrc string `json:"thumbnail_src"`
IsVideo bool `json:"is_video"`
Code string `json:"code"`
Date int `json:"date"`
DisplaySrc string `json:"display_src"`
Caption string `json:"caption"`
Comments struct {
Count int `json:"count"`
} `json:"comments"`
Likes struct {
Count int `json:"count"`
} `json:"likes"`
} `json:"nodes"`
} `json:"top_posts"`
} `json:"tag"`
}
// PostResponse defines the instagram post response
type PostResponse struct {
Graphql struct {
ShortcodeMedia struct {
Typename string `json:"__typename"`
ID string `json:"id"`
Shortcode string `json:"shortcode"`
Dimensions struct {
Height int `json:"height"`
Width int `json:"width"`
} `json:"dimensions"`
DisplayURL string `json:"display_url"`
VideoURL string `json:"video_url"`
VideoViewCount int `json:"video_view_count"`
IsVideo bool `json:"is_video"`
EdgeMediaToTaggedUser struct {
Edges []interface{} `json:"edges"`
} `json:"edge_media_to_tagged_user"`
EdgeMediaToCaption struct {
Edges []struct {
Node struct {
Text string `json:"text"`
} `json:"node"`
} `json:"edges"`
} `json:"edge_media_to_caption"`
CaptionIsEdited bool `json:"caption_is_edited"`
EdgeMediaToComment struct {
Count int `json:"count"`
PageInfo struct {
HasNextPage bool `json:"has_next_page"`
EndCursor string `json:"end_cursor"`
} `json:"page_info"`
Edges []struct {
Node struct {
ID string `json:"id"`
Text string `json:"text"`
CreatedAt int `json:"created_at"`
Owner struct {
ID string `json:"id"`
ProfilePicURL string `json:"profile_pic_url"`
Username string `json:"username"`
} `json:"owner"`
} `json:"node"`
} `json:"edges"`
} `json:"edge_media_to_comment"`
CommentsDisabled bool `json:"comments_disabled"`
TakenAtTimestamp int `json:"taken_at_timestamp"`
EdgeMediaPreviewLike struct {
Count int `json:"count"`
Edges []struct {
Node struct {
ID string `json:"id"`
ProfilePicURL string `json:"profile_pic_url"`
Username string `json:"username"`
} `json:"node"`
} `json:"edges"`
} `json:"edge_media_preview_like"`
EdgeMediaToSponsorUser struct {
Edges []interface{} `json:"edges"`
} `json:"edge_media_to_sponsor_user"`
Location interface{} `json:"location"`
ViewerHasLiked bool `json:"viewer_has_liked"`
Owner struct {
ID string `json:"id"`
ProfilePicURL string `json:"profile_pic_url"`
Username string `json:"username"`
FollowedByViewer bool `json:"followed_by_viewer"`
FullName string `json:"full_name"`
IsPrivate bool `json:"is_private"`
RequestedByViewer bool `json:"requested_by_viewer"`
IsUnpublished bool `json:"is_unpublished"`
BlockedByViewer bool `json:"blocked_by_viewer"`
HasBlockedViewer bool `json:"has_blocked_viewer"`
} `json:"owner"`
IsAd bool `json:"is_ad"`
EdgeWebMediaToRelatedMedia struct {
Edges []interface{} `json:"edges"`
} `json:"edge_web_media_to_related_media"`
} `json:"shortcode_media"`
} `json:"graphql"`
}
// LoadList loads the media list of a instagram page
func LoadList(token string) (*ListResponse, error) {
var listResponse ListResponse
var url string
if token == "" {
url = "https://www.instagram.com/explore/tags/" + config.C.Instagram.Tag + "/?__a=1"
} else {
url = "https://www.instagram.com/explore/tags/" + config.C.Instagram.Tag + "/?__a=1&max_id=" + token
}
res, err := GetHTTPResource(url)
if err != nil {
return nil, err
}
defer res.Body.Close()
body, err := ioutil.ReadAll(res.Body)
if err != nil {
return nil, err
}
jerr := json.Unmarshal(body, &listResponse)
if jerr != nil {
return nil, jerr
}
return &listResponse, nil
}
// LoadPost loads single post from instagram
func LoadPost(code string) (*PostResponse, error) {
var postResponse PostResponse
res, err := GetHTTPResource("https://www.instagram.com/p/" + code + "/?__a=1")
if err != nil {
return nil, err
}
defer res.Body.Close()
body, err := ioutil.ReadAll(res.Body)
if err != nil {
return nil, err
}
jerr := json.Unmarshal(body, &postResponse)
if jerr != nil {
return nil, jerr
}
return &postResponse, nil
}
// ImageNameGenerator generates media paths
func ImageNameGenerator(seed string) (string, string) {
seedBytes := []byte(seed)
sha256Bytes := sha256.Sum256(seedBytes)
hash := hex.EncodeToString(sha256Bytes[:])
folders := config.C.ContentDirectory + "/" + hash[0:2] + "/" + hash[0:4] + "/"
urls := config.C.ContentWebDirectory + "/" + hash[0:2] + "/" + hash[0:4] + "/"
if err := os.MkdirAll(folders, 0775); err != nil {
log.Fatalf("FAT Could not create ContentDirectory, error: %+v", err)
}
finalPath := folders + hash
finalURL := urls + hash
return finalPath, finalURL
}
// DownloadMedia downloads given media from Instagram
func DownloadMedia(data io.Reader, path string, video bool) (string, error) {
if video {
ext := ".mp4"
blob, err := ioutil.ReadAll(data)
if err != nil {
return "", err
}
if len(blob) == 0 {
return "", errors.New("Empty response")
}
err = ioutil.WriteFile(path+ext, blob, 0644)
if err != nil {
return "", err
}
return ext, nil
}
ext := ".jpg"
image, err := imaging.Decode(data)
if err != nil {
return "", err
}
err = imaging.Save(image, path+ext)
if err != nil {
return "", err
}
return ext, nil
}