forked from youtube/api-samples
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsearch_by_topic.go
More file actions
173 lines (150 loc) · 4.16 KB
/
search_by_topic.go
File metadata and controls
173 lines (150 loc) · 4.16 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
package main
import (
"encoding/json"
"errors"
"flag"
"fmt"
"io/ioutil"
"log"
"net/http"
"net/url"
"os"
"code.google.com/p/google-api-go-client/googleapi/transport"
"code.google.com/p/google-api-go-client/youtube/v3"
)
var (
query = flag.String("query", "Google", "Freebase search term")
maxResults = flag.Int64("max-results", 25, "Max YouTube results")
resultType = flag.String("type", "channel", "YouTube result type: video, playlist, or channel")
)
const developerKey = "YOUR DEVELOPER KEY HERE"
const freebaseSearchURL = "https://www.googleapis.com/freebase/v1/search?%s"
// Notable is struct for unmarshalling JSON values from the API.
type Notable struct {
Name string
ID string
}
// FreebaseTopic is struct for unmarshalling JSON values from the API.
type FreebaseTopic struct {
Mid string
ID string
Name string
Notable Notable
Lang string
Score float64
}
// FreebaseResponse is struct for unmarshalling JSON values from the Freebase API.
type FreebaseResponse struct {
Status string
Result []FreebaseTopic
}
func main() {
flag.Parse()
topicID, err := getTopicID(*query)
if err != nil {
log.Fatalf("Cannot fetch topic ID from Freebase: %v", err)
}
err = youtubeSearch(topicID)
if err != nil {
log.Fatalf("Cannot make YouTube API call: %v", err)
}
}
// getTopicID queries Freebase with the given string. It then prompts the user
// to select a topic, then returns the selected topic so that the topic can be
// used to search YouTube for videos, channels or playlists.
func getTopicID(topic string) (string, error) {
urlParams := url.Values{
"query": []string{topic},
"key": []string{developerKey},
}
apiURL := fmt.Sprintf(freebaseSearchURL, urlParams.Encode())
resp, err := http.Get(apiURL)
if err != nil {
return "", err
} else if resp.StatusCode != http.StatusOK {
errorMsg := fmt.Sprintf("Received HTTP status code %v using developer key: %v",
resp.StatusCode, developerKey)
return "", errors.New(errorMsg)
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return "", err
}
var data FreebaseResponse
err = json.Unmarshal(body, &data)
if err != nil {
return "", nil
}
if len(data.Result) == 0 {
return "", errors.New("No matching terms were found in Freebase.")
}
// Print a list of topics for the user to select.
fmt.Println("The following topics were found:")
for index, topic := range data.Result {
if topic.Notable.Name == "" {
topic.Notable.Name = "Unknown"
}
fmt.Printf(" %2d. %s (%s)\r\n", index+1, topic.Name, topic.Notable.Name)
}
prompt := fmt.Sprintf("Enter a topic number to find related YouTube %s [1-%v]: ",
*resultType, len(data.Result))
selection, err := readInt(prompt, 1, len(data.Result))
if err != nil {
return "", nil
}
choice := data.Result[selection-1]
return choice.Mid, nil
}
// readInt reads an integer from standard input and verifies that the value
// is between the allowed min and max values (inclusive).
func readInt(prompt string, min int, max int) (int, error) {
// Loop until we have a valid input.
for {
fmt.Print(prompt)
var i int
_, err := fmt.Fscan(os.Stdin, &i)
if err != nil {
return 0, err
}
if i < min || i > max {
fmt.Println("Invalid input.")
continue
}
return i, nil
}
}
// youtubeSearch searches YouTube for the topic given in the query flag and
// prints the results. This function takes a mid parameter, which specifies
// a value retrieved using the Freebase API.
func youtubeSearch(mid string) error {
client := &http.Client{
Transport: &transport.APIKey{Key: developerKey},
}
service, err := youtube.New(client)
if err != nil {
return err
}
// Make the API call to YouTube.
call := service.Search.List("id,snippet").
TopicId(mid).
Type(*resultType).
MaxResults(*maxResults)
response, err := call.Do()
if err != nil {
return err
}
// Iterate through each item and output it.
for _, item := range response.Items {
itemID := ""
switch item.Id.Kind {
case "youtube#video":
itemID = item.Id.VideoId
case "youtube#channel":
itemID = item.Id.ChannelId
case "youtube#playlist":
itemID = item.Id.PlaylistId
}
fmt.Printf("%v (%v)\r\n", item.Snippet.Title, itemID)
}
return nil
}