Skip to content

Commit b9addf8

Browse files
"Added sample: java/src/main/java/com/google/api/services/samples/youtube/cmdline/data/Topics.java"
1 parent f1e80ee commit b9addf8

File tree

1 file changed

+349
-0
lines changed
  • java/src/main/java/com/google/api/services/samples/youtube/cmdline/data

1 file changed

+349
-0
lines changed
Lines changed: 349 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,349 @@
1+
/*
2+
* Copyright (c) 2012 Google Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5+
* in compliance with the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the
10+
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
11+
* express or implied. See the License for the specific language governing permissions and
12+
* limitations under the License.
13+
*/
14+
15+
package com.google.api.services.samples.youtube.cmdline.data;
16+
17+
import com.google.api.client.googleapis.json.GoogleJsonResponseException;
18+
import com.google.api.client.http.HttpRequest;
19+
import com.google.api.client.http.HttpRequestInitializer;
20+
import com.google.api.services.samples.youtube.cmdline.Auth;
21+
import com.google.api.services.youtube.YouTube;
22+
import com.google.api.services.youtube.model.ResourceId;
23+
import com.google.api.services.youtube.model.SearchListResponse;
24+
import com.google.api.services.youtube.model.SearchResult;
25+
import com.google.api.services.youtube.model.Thumbnail;
26+
import org.apache.http.HttpEntity;
27+
import org.apache.http.HttpResponse;
28+
import org.apache.http.NameValuePair;
29+
import org.apache.http.client.HttpClient;
30+
import org.apache.http.client.methods.HttpGet;
31+
import org.apache.http.client.utils.URLEncodedUtils;
32+
import org.apache.http.impl.client.DefaultHttpClient;
33+
import org.apache.http.message.BasicNameValuePair;
34+
import org.codehaus.jackson.JsonNode;
35+
import org.codehaus.jackson.map.ObjectMapper;
36+
import org.codehaus.jackson.node.ArrayNode;
37+
38+
import java.io.BufferedReader;
39+
import java.io.IOException;
40+
import java.io.InputStream;
41+
import java.io.InputStreamReader;
42+
import java.util.ArrayList;
43+
import java.util.Iterator;
44+
import java.util.List;
45+
import java.util.Properties;
46+
import java.util.regex.Matcher;
47+
import java.util.regex.Pattern;
48+
49+
/**
50+
* This application demonstrates a semantic YouTube search that prompts the
51+
* user to enter a search term and select a topic related to that term. The
52+
* class calls the Freebase API to get a topic ID, then passes that id along
53+
* with another user query term to the YouTube APIs. The result is a list of
54+
* videos based on a semantic search.
55+
*
56+
* @author Jeremy Walker
57+
*/
58+
public class Topics {
59+
60+
/**
61+
* Define a global variable that identifies the name of a file that
62+
* contains the developer's API key.
63+
*/
64+
private static final String PROPERTIES_FILENAME = "youtube.properties";
65+
66+
/**
67+
* Define a global variable that specifies the maximum number of videos
68+
* that an API response can contain.
69+
*/
70+
private static final long NUMBER_OF_VIDEOS_RETURNED = 5;
71+
72+
/**
73+
* Define a global variable that specifies the maximum number of topics
74+
* that an API response can contain.
75+
*/
76+
private static final long NUMBER_OF_TOPICS_RETURNED = 5;
77+
78+
/**
79+
* Define a global instance of a Youtube object, which will be used
80+
* to make YouTube Data API requests.
81+
*/
82+
private static YouTube youtube;
83+
84+
/**
85+
* Execute a search request that starts by calling the Freebase API to
86+
* retrieve a topic ID matching a user-provided term. Then initialize a
87+
* YouTube object to search for YouTube videos and call the YouTube Data
88+
* API's youtube.search.list method to retrieve a list of videos associated
89+
* with the selected Freebase topic and with another search query term,
90+
* which the user also enters. Finally, display the titles, video IDs, and
91+
* thumbnail images for the first five videos in the YouTube Data API
92+
* response.
93+
*
94+
* @param args This application does not use command line arguments.
95+
*/
96+
public static void main(String[] args) {
97+
// Read the developer key from the properties file.
98+
Properties properties = new Properties();
99+
try {
100+
InputStream in = Topics.class.getResourceAsStream("/" + PROPERTIES_FILENAME);
101+
properties.load(in);
102+
103+
} catch (IOException e) {
104+
System.err.println("There was an error reading " + PROPERTIES_FILENAME + ": " + e.getCause()
105+
+ " : " + e.getMessage());
106+
System.exit(1);
107+
}
108+
109+
110+
try {
111+
// Retrieve a Freebase topic ID based on a user-entered query term.
112+
String topicsId = getTopicId();
113+
if (topicsId.length() < 1) {
114+
System.out.println("No topic id will be applied to your search.");
115+
}
116+
117+
// Prompt the user to enter a search query term. This term will be
118+
// used to retrieve YouTube search results related to the topic
119+
// selected above.
120+
String queryTerm = getInputQuery("search");
121+
122+
// This object is used to make YouTube Data API requests. The last
123+
// argument is required, but since we don't need anything
124+
// initialized when the HttpRequest is initialized, we override
125+
// the interface and provide a no-op function.
126+
youtube = new YouTube.Builder(Auth.HTTP_TRANSPORT, Auth.JSON_FACTORY, new HttpRequestInitializer() {
127+
public void initialize(HttpRequest request) throws IOException {
128+
}
129+
})
130+
.setApplicationName("youtube-cmdline-search-sample")
131+
.build();
132+
133+
YouTube.Search.List search = youtube.search().list("id,snippet");
134+
135+
// Set your developer key from the {{ Google Cloud Console }} for
136+
// non-authenticated requests. See:
137+
// {{ https://cloud.google.com/console }}
138+
String apiKey = properties.getProperty("youtube.apikey");
139+
search.setKey(apiKey);
140+
search.setQ(queryTerm);
141+
if (topicsId.length() > 0) {
142+
search.setTopicId(topicsId);
143+
}
144+
145+
// Restrict the search results to only include videos. See:
146+
// https://developers.google.com/youtube/v3/docs/search/list#type
147+
search.setType("video");
148+
149+
// To increase efficiency, only retrieve the fields that the
150+
// application uses.
151+
search.setFields("items(id/kind,id/videoId,snippet/title,snippet/thumbnails/default/url)");
152+
search.setMaxResults(NUMBER_OF_VIDEOS_RETURNED);
153+
SearchListResponse searchResponse = search.execute();
154+
155+
List<SearchResult> searchResultList = searchResponse.getItems();
156+
157+
if (searchResultList != null) {
158+
prettyPrint(searchResultList.iterator(), queryTerm, topicsId);
159+
} else {
160+
System.out.println("There were no results for your query.");
161+
}
162+
} catch (GoogleJsonResponseException e) {
163+
System.err.println("There was a service error: " + e.getDetails().getCode() +
164+
" : " + e.getDetails().getMessage());
165+
e.printStackTrace();
166+
} catch (IOException e) {
167+
System.err.println("There was an IO error: " + e.getCause() + " : " + e.getMessage());
168+
e.printStackTrace();
169+
}
170+
}
171+
172+
/*
173+
* Prompt the user to enter a search term and return the user's input.
174+
*
175+
* @param searchCategory This value is displayed to the user to clarify the information that the application is requesting.
176+
*/
177+
private static String getInputQuery(String searchCategory) throws IOException {
178+
179+
String inputQuery = "";
180+
181+
BufferedReader bReader = new BufferedReader(new InputStreamReader(System.in));
182+
183+
do {
184+
System.out.print("Please enter a " + searchCategory + " term: ");
185+
inputQuery = bReader.readLine();
186+
} while (inputQuery.length() < 1);
187+
188+
return inputQuery;
189+
}
190+
191+
/**
192+
* Retrieve Freebase topics that match a user-provided query term. Then
193+
* prompt the user to select a topic and return its topic ID.
194+
*/
195+
private static String getTopicId() throws IOException {
196+
197+
// The application will return an empty string if no matching topic ID
198+
// is found or no results are available.
199+
String topicsId = "";
200+
201+
// Prompt the user to enter a query term for finding Freebase topics.
202+
String topicQuery = getInputQuery("topics");
203+
204+
// The Freebase Java library does not provide search functionality, so
205+
// the application needs to call directly against the URL. This code
206+
// constructs the proper URL, then uses jackson classes to convert the
207+
// JSON response into a Java object. You can learn more about the
208+
// Freebase search calls at: http://wiki.freebase.com/wiki/ApiSearch.
209+
HttpClient httpclient = new DefaultHttpClient();
210+
List<NameValuePair> params = new ArrayList<NameValuePair>();
211+
params.add(new BasicNameValuePair("query", topicQuery));
212+
params.add(new BasicNameValuePair("limit", Long.toString(NUMBER_OF_TOPICS_RETURNED)));
213+
214+
String serviceURL = "https://www.googleapis.com/freebase/v1/search";
215+
String url = serviceURL + "?" + URLEncodedUtils.format(params, "UTF-8");
216+
217+
HttpResponse httpResponse = httpclient.execute(new HttpGet(url));
218+
HttpEntity entity = httpResponse.getEntity();
219+
220+
if (entity != null) {
221+
InputStream instream = entity.getContent();
222+
try {
223+
224+
// Convert the JSON to an object. This code does not do an
225+
// exact map from JSON to POJO (Plain Old Java object), but
226+
// you could create additional classes and use them with the
227+
// mapper.readValue() function to get that exact mapping.
228+
ObjectMapper mapper = new ObjectMapper();
229+
JsonNode rootNode = mapper.readValue(instream, JsonNode.class);
230+
231+
// Confirm that the HTTP request was handled successfully by
232+
// checking the API response's HTTP response code.
233+
if (rootNode.get("status").asText().equals("200 OK")) {
234+
// In the API response, the "result" field contains the
235+
// list of needed results.
236+
ArrayNode arrayNodeResults = (ArrayNode) rootNode.get("result");
237+
// Prompt the user to select a topic from the list of API
238+
// results.
239+
topicsId = getUserChoice(arrayNodeResults);
240+
}
241+
} finally {
242+
instream.close();
243+
}
244+
}
245+
return topicsId;
246+
}
247+
248+
/**
249+
* Output results from the Freebase topic search to the user, prompt the
250+
* user to select a topic, and return the appropriate topic ID.
251+
*
252+
* @param freebaseResults ArrayNode This object contains the search results.
253+
*/
254+
private static String getUserChoice(ArrayNode freebaseResults) throws IOException {
255+
256+
String freebaseId = "";
257+
258+
if (freebaseResults.size() < 1) {
259+
return freebaseId;
260+
}
261+
262+
// Print a list of topics retrieved from Freebase.
263+
for (int i = 0; i < freebaseResults.size(); i++) {
264+
JsonNode node = freebaseResults.get(i);
265+
System.out.print(" " + i + " = " + node.get("name").asText());
266+
if (node.get("notable") != null) {
267+
System.out.print(" (" + node.get("notable").get("name").asText() + ")");
268+
}
269+
System.out.println("");
270+
}
271+
272+
BufferedReader bReader = new BufferedReader(new InputStreamReader(System.in));
273+
String inputChoice;
274+
275+
// Prompt the user to select a topic.
276+
do {
277+
System.out.print("Choose the number of the Freebase Node: ");
278+
inputChoice = bReader.readLine();
279+
} while (!isValidIntegerSelection(inputChoice, freebaseResults.size()));
280+
281+
// Return the topic ID needed for the API request that retrieves
282+
// YouTube search results.
283+
JsonNode node = freebaseResults.get(Integer.parseInt(inputChoice));
284+
freebaseId = node.get("mid").asText();
285+
return freebaseId;
286+
}
287+
288+
/**
289+
* Confirm that the string represents a valid, positive integer, that is
290+
* less than or equal to 999,999,999. (Since the API will not return a
291+
* billion results for a query, any integer that the user enters will need
292+
* to be less than that to be valid, anyway.)
293+
*
294+
* @param input The string to test.
295+
* @param max The integer must be less then this maximum number.
296+
*/
297+
public static boolean isValidIntegerSelection(String input, int max) {
298+
if (input.length() > 9)
299+
return false;
300+
301+
boolean validNumber = false;
302+
// Only accept positive numbers with a maximum of nine digits.
303+
Pattern intsOnly = Pattern.compile("^\\d{1,9}$");
304+
Matcher makeMatch = intsOnly.matcher(input);
305+
306+
if (makeMatch.find()) {
307+
int number = Integer.parseInt(makeMatch.group());
308+
if ((number >= 0) && (number < max)) {
309+
validNumber = true;
310+
}
311+
}
312+
return validNumber;
313+
}
314+
315+
/*
316+
* Prints out all results in the Iterator. For each result, print the
317+
* title, video ID, and thumbnail.
318+
*
319+
* @param iteratorSearchResults Iterator of SearchResults to print
320+
* @param query Search query (String)
321+
*/
322+
private static void prettyPrint(Iterator<SearchResult> iteratorSearchResults, String query, String topicsId) {
323+
324+
System.out.println("\n=============================================================");
325+
System.out.println(" First " + NUMBER_OF_VIDEOS_RETURNED + " videos for search on \"" + query + "\" with Topics id: " + topicsId + ".");
326+
System.out.println("=============================================================\n");
327+
328+
if (!iteratorSearchResults.hasNext()) {
329+
System.out.println(" There aren't any results for your query.");
330+
}
331+
332+
while (iteratorSearchResults.hasNext()) {
333+
334+
SearchResult singleVideo = iteratorSearchResults.next();
335+
ResourceId rId = singleVideo.getId();
336+
337+
// Confirm that the result represents a video. Otherwise, the
338+
// item will not contain a video ID.
339+
if (rId.getKind().equals("youtube#video")) {
340+
Thumbnail thumbnail = singleVideo.getSnippet().getThumbnails().getDefault();
341+
342+
System.out.println(" Video Id" + rId.getVideoId());
343+
System.out.println(" Title: " + singleVideo.getSnippet().getTitle());
344+
System.out.println(" Thumbnail: " + thumbnail.getUrl());
345+
System.out.println("\n-------------------------------------------------------------\n");
346+
}
347+
}
348+
}
349+
}

0 commit comments

Comments
 (0)