215 lines
5 KiB
Go
215 lines
5 KiB
Go
|
package youtube
|
||
|
|
||
|
import (
|
||
|
"encoding/json"
|
||
|
"net/http"
|
||
|
"net/url"
|
||
|
"io/ioutil"
|
||
|
"strings"
|
||
|
"errors"
|
||
|
"log"
|
||
|
"fmt"
|
||
|
)
|
||
|
|
||
|
type Thumb struct {
|
||
|
Url string
|
||
|
Width int
|
||
|
Height int
|
||
|
}
|
||
|
|
||
|
type Snip struct {
|
||
|
PublishedAt string
|
||
|
Title string
|
||
|
Description string
|
||
|
Thumbnails map[string]Thumb
|
||
|
}
|
||
|
|
||
|
type ContentD struct {
|
||
|
Duration string
|
||
|
}
|
||
|
|
||
|
type Stats struct {
|
||
|
LikeCount int64 `json:",string"`
|
||
|
DislikeCount int64 `json:",string"`
|
||
|
}
|
||
|
|
||
|
type Stat struct {
|
||
|
UploadStatus string
|
||
|
PrivacyStatus string
|
||
|
}
|
||
|
|
||
|
type BrandingSetting struct {
|
||
|
Image map[string]string
|
||
|
}
|
||
|
|
||
|
type Error struct {
|
||
|
Code int
|
||
|
Message string
|
||
|
}
|
||
|
|
||
|
type Item struct {
|
||
|
Id string
|
||
|
Snippet Snip
|
||
|
ContentDetails ContentD
|
||
|
Status Stat
|
||
|
Statistics Stats
|
||
|
BrandingSettings BrandingSetting
|
||
|
}
|
||
|
|
||
|
type YTResult struct {
|
||
|
Items []Item
|
||
|
Error *Error
|
||
|
}
|
||
|
|
||
|
var videoEndpoint string = "https://www.googleapis.com/youtube/v3/videos"
|
||
|
var channelEndpoint string = "https://www.googleapis.com/youtube/v3/channels"
|
||
|
var sem = make(chan byte, 10)
|
||
|
|
||
|
|
||
|
// Make an HTTP Get Request to u
|
||
|
func GetHTTPResource(u string) (*http.Response, error) {
|
||
|
sem <- 1
|
||
|
// Prepare HTTP Client, Cookie and Request
|
||
|
res, err := http.Get(u)
|
||
|
if err != nil {
|
||
|
log.Printf("[WARN] HTTP - Request to %s failed: %s", u, err)
|
||
|
<- sem
|
||
|
return nil, err
|
||
|
}
|
||
|
if res.StatusCode == http.StatusNotFound {
|
||
|
log.Printf("[WARN] HTTP - Received 404 Not Found for: %s", u)
|
||
|
<- sem
|
||
|
return nil, nil
|
||
|
}
|
||
|
<- sem
|
||
|
return res, nil
|
||
|
}
|
||
|
|
||
|
func GetVideos(parts []string, ids []string, key string) (*YTResult, error) {
|
||
|
var ytVideo YTResult
|
||
|
|
||
|
u, _ := url.Parse(videoEndpoint)
|
||
|
query := u.Query()
|
||
|
|
||
|
// Stringify arraysfmt
|
||
|
p := strings.Join(parts, ",")
|
||
|
i := strings.Join(ids, ",")
|
||
|
|
||
|
// Set params in URL Query
|
||
|
query.Set("part", p)
|
||
|
query.Set("id", i)
|
||
|
query.Set("key", key)
|
||
|
u.RawQuery = query.Encode()
|
||
|
res, err := GetHTTPResource(u.String())
|
||
|
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, &ytVideo)
|
||
|
if jerr != nil {
|
||
|
return nil, jerr
|
||
|
}
|
||
|
return &ytVideo, nil
|
||
|
}
|
||
|
|
||
|
func GetChannel(parts []string, id string, key string) (*YTResult, error) {
|
||
|
var ytRes YTResult
|
||
|
|
||
|
u, _ := url.Parse(channelEndpoint)
|
||
|
query := u.Query()
|
||
|
|
||
|
// Stringify array
|
||
|
p := strings.Join(parts, ",")
|
||
|
|
||
|
// Set params in URL Query
|
||
|
query.Set("part", p)
|
||
|
query.Set("id", id)
|
||
|
query.Set("key", key)
|
||
|
u.RawQuery = query.Encode()
|
||
|
res, err := GetHTTPResource(u.String())
|
||
|
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, &ytRes)
|
||
|
if jerr != nil {
|
||
|
return nil, jerr
|
||
|
}
|
||
|
if ytRes.Error != nil {
|
||
|
return nil, fmt.Errorf("Youtube Error: %+v: %s", ytRes.Error.Code, ytRes.Error.Message)
|
||
|
}
|
||
|
return &ytRes, nil
|
||
|
}
|
||
|
|
||
|
func GetChannelId(name string, key string) (string, error) {
|
||
|
var ytRes YTResult
|
||
|
|
||
|
u, _ := url.Parse(channelEndpoint)
|
||
|
query := u.Query()
|
||
|
|
||
|
// Set params in URL Query
|
||
|
query.Set("part", "snippet")
|
||
|
query.Set("forUsername", name)
|
||
|
query.Set("key", key)
|
||
|
u.RawQuery = query.Encode()
|
||
|
res, err := GetHTTPResource(u.String())
|
||
|
if err != nil {
|
||
|
return "", err
|
||
|
}
|
||
|
defer res.Body.Close()
|
||
|
body, err := ioutil.ReadAll(res.Body)
|
||
|
if err != nil {
|
||
|
return "", err
|
||
|
}
|
||
|
jerr := json.Unmarshal(body, &ytRes)
|
||
|
if jerr != nil {
|
||
|
return "", jerr
|
||
|
}
|
||
|
if len(ytRes.Items) < 0 {
|
||
|
return "", errors.New("API Error")
|
||
|
}
|
||
|
return ytRes.Items[0].Id, nil
|
||
|
}
|
||
|
|
||
|
func GetRatingAndVotesWithId(id string, key string) (float64, int64, string, Thumb) {
|
||
|
ytres, err := GetVideos([]string {"statistics", "status", "snippet"}, []string {id}, key)
|
||
|
if err != nil || len(ytres.Items) == 0 {
|
||
|
return 0, 0, "private", Thumb{}
|
||
|
}
|
||
|
votes := ytres.Items[0].Statistics.LikeCount + ytres.Items[0].Statistics.DislikeCount
|
||
|
var rating float64
|
||
|
if ytres.Items[0].Statistics.LikeCount != 0 {
|
||
|
rating = (float64(ytres.Items[0].Statistics.LikeCount)/float64(votes))*10
|
||
|
} else {
|
||
|
rating = 0
|
||
|
}
|
||
|
status := ytres.Items[0].Status.PrivacyStatus
|
||
|
if ytres.Items[0].Status.UploadStatus != "processed" {
|
||
|
status = "private"
|
||
|
}
|
||
|
thumb, ok := ytres.Items[0].Snippet.Thumbnails["maxres"]
|
||
|
if !ok {
|
||
|
thumb, ok = ytres.Items[0].Snippet.Thumbnails["high"]
|
||
|
}
|
||
|
return rating, votes, status, thumb
|
||
|
}
|
||
|
|
||
|
func GetRatingAndVotesWithRes(ytres *YTResult) (float64, int64) {
|
||
|
votes := ytres.Items[0].Statistics.LikeCount + ytres.Items[0].Statistics.DislikeCount
|
||
|
var rating float64
|
||
|
if ytres.Items[0].Statistics.LikeCount != 0 {
|
||
|
rating = (float64(ytres.Items[0].Statistics.LikeCount)/float64(votes))*10
|
||
|
} else {
|
||
|
rating = 0
|
||
|
}
|
||
|
return rating, votes
|
||
|
}
|