-
-
Save mlarocca/6717b49df8ca39410cb7 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
application: pweb-14 | |
version: 1 | |
runtime: python27 | |
api_version: 1 | |
threadsafe: yes | |
handlers: | |
- url: /favicon\.ico | |
static_files: favicon.ico | |
upload: favicon\.ico | |
- url: / | |
static_files: static/index.html | |
upload: / | |
- url: /json.* | |
script: main.app | |
- url: /videos.* | |
script: videos.app | |
libraries: | |
- name: webapp2 | |
version: "2.5.2" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# | |
# Copyright 2007 Google Inc. | |
# | |
# Licensed under the Apache License, Version 2.0 (the "License"); | |
# you may not use this file except in compliance with the License. | |
# You may obtain a copy of the License at | |
# | |
# http://www.apache.org/licenses/LICENSE-2.0 | |
# | |
# Unless required by applicable law or agreed to in writing, software | |
# distributed under the License is distributed on an "AS IS" BASIS, | |
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
# See the License for the specific language governing permissions and | |
# limitations under the License. | |
# | |
import webapp2 | |
import json | |
from apiclient.discovery import build | |
from apiclient.errors import HttpError | |
# Set DEVELOPER_KEY to the API key value from the APIs & auth > Registered apps | |
# tab of | |
# https://cloud.google.com/console | |
# Please ensure that you have enabled the YouTube Data API for your project. | |
DEVELOPER_KEY = "REPLACE_ME" | |
YOUTUBE_API_SERVICE_NAME = "youtube" | |
YOUTUBE_API_VERSION = "v3" | |
def youtube_search(query, max_results=20): | |
youtube = build(YOUTUBE_API_SERVICE_NAME, YOUTUBE_API_VERSION, developerKey=DEVELOPER_KEY) | |
# Call the search.list method to retrieve results matching the specified | |
# query term. | |
search_response = youtube.search().list( | |
q=query, | |
part="id,snippet", | |
maxResults=max_results, | |
type="video" | |
).execute() | |
#extract only a few 'interesting' fields from the data | |
result_transform = lambda search_result: { | |
'id': search_result['id']['videoId'], | |
'title': search_result['snippet']['title'], | |
'thumbnail': search_result['snippet']['thumbnails']['default']['url'], | |
'date': search_result['snippet']['publishedAt'] | |
} | |
# Filter results to retaun only matching videos, and filter out channels and playlists. | |
return map(result_transform, search_response.get("items", [])) | |
class MainHandler(webapp2.RequestHandler): | |
def get(self): | |
self.error(404) #just an example to show you how to return an error | |
class JsonHandler(webapp2.RequestHandler): | |
def get(self): | |
query = self.request.get('query', default_value=None) | |
if query and len(query) >= 2: | |
try: | |
query_result = youtube_search(query) | |
except HttpError, e: | |
self.response.headers['Content-Type'] = 'text/plain' | |
self.response.out.write("An HTTP error %d occurred:\n%s" % (e.resp.status, e.content)) | |
return | |
else: | |
query_result = [] | |
self.response.headers['Content-Type'] = 'application/json' | |
self.response.out.write(json.dumps(query_result)) | |
app = webapp2.WSGIApplication([ | |
('/', MainHandler), | |
('/json/?', JsonHandler) | |
], debug=True) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# | |
# Copyright 2007 Google Inc. | |
# | |
# Licensed under the Apache License, Version 2.0 (the "License"); | |
# you may not use this file except in compliance with the License. | |
# You may obtain a copy of the License at | |
# | |
# http://www.apache.org/licenses/LICENSE-2.0 | |
# | |
# Unless required by applicable law or agreed to in writing, software | |
# distributed under the License is distributed on an "AS IS" BASIS, | |
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
# See the License for the specific language governing permissions and | |
# limitations under the License. | |
# | |
import webapp2 | |
import json | |
from apiclient.discovery import build | |
from apiclient.errors import HttpError | |
# Set DEVELOPER_KEY to the API key value from the APIs & auth > Registered apps | |
# tab of | |
# https://cloud.google.com/console | |
# Please ensure that you have enabled the YouTube Data API for your project. | |
DEVELOPER_KEY = "REPLACE_ME" | |
YOUTUBE_API_SERVICE_NAME = "youtube" | |
YOUTUBE_API_VERSION = "v3" | |
YOUTUBE_MAX_RESULTS_PER_PAGE = 50 | |
class VideoSearchHandler(webapp2.RequestHandler): | |
#list all the possible valid values for the order | |
__VALID_ORDER_CRITERIA = set(['date', 'rating', 'relevance', 'title', 'videoCount', 'viewCount']) | |
__DEFAULT_SORTING_CRITERION = 'relevance' | |
def __validate_order(self, criterion): | |
""" Validate the criterion passed, by verifying it is among the ones acceptable by the API | |
""" | |
return criterion if criterion in VideoSearchHandler.__VALID_ORDER_CRITERIA else VideoSearchHandler.__DEFAULT_SORTING_CRITERION | |
def __extract_positive_int(self, param_name, default_value): | |
try: | |
v = int(self.request.get(param_name, default_value=default_value)) | |
if v <= 0: | |
return default_value | |
else: | |
return v | |
except TypeError: | |
return default_value | |
def __extract_params(self): | |
return { | |
'first_result': self.__extract_positive_int('first_result', 1), | |
'max_results': self.__extract_positive_int('max_results', None), | |
'order': self.__validate_order(self.request.get('order', default_value=None)) | |
} | |
def __search_youtube_videos(self, keywords, params, related_id, regionCode): | |
youtube = build(YOUTUBE_API_SERVICE_NAME, YOUTUBE_API_VERSION, developerKey=DEVELOPER_KEY) | |
# Filter results to retaun only matching videos, and filter out channels and playlists. | |
result_transform = lambda search_result: { | |
'id': search_result['id']['videoId'], | |
'title': search_result['snippet']['title'], | |
'thumbnail': search_result['snippet']['thumbnails']['default'], | |
'date': search_result['snippet']['publishedAt'] | |
} | |
#prepare the parameters for the list method | |
search_params = { | |
'q':keywords, | |
'part':"id,snippet", | |
'type':'video' | |
} | |
if not related_id is None: | |
search_params['relatedToVideoId'] = related_id | |
if not regionCode is None: | |
search_params['regionCode'] = regionCode | |
if not params['order'] is None: | |
search_params['order'] = params['order'] | |
first_result = params['first_result'] if 'first_result' in params else 1 | |
#To leave things simple, it checks that the first and last result fall in the first results page | |
if first_result >= YOUTUBE_MAX_RESULTS_PER_PAGE: | |
raise HttpError("Invalid parameter: first_result must be lower than %d" % YOUTUBE_MAX_RESULTS_PER_PAGE, 403) | |
if not params['max_results'] is None: | |
max_result = first_result + params['max_results'] | |
search_params['maxResults'] = max_result | |
#To leave things simple, it checks that the first and last result fall in the first results page | |
if max_result > YOUTUBE_MAX_RESULTS_PER_PAGE: | |
max_result = YOUTUBE_MAX_RESULTS_PER_PAGE | |
search_params['maxResults'] = max_result | |
# Call the search.list method to retrieve results matching the keywords. | |
search_response = youtube.search().list( | |
**search_params #unpack the dictionary to a list of named parameters | |
).execute() | |
return map(result_transform, search_response.get("items", [])[first_result:search_response['pageInfo']['totalResults']]) | |
def search_videos(self, keywords, related_id=None, regionCode=None): | |
params = self.__extract_params() | |
self.return_results(self.__search_youtube_videos(keywords, params=params, related_id=related_id, regionCode=regionCode)) | |
def return_results(self, results): | |
self.response.headers['Content-Type'] = 'application/json' | |
self.response.out.write(json.dumps(results)) | |
class SimpleVideoSearchHandler(VideoSearchHandler): | |
def get(self, keywords): | |
self.search_videos(keywords) | |
class RelatedVideoSearchHandler(VideoSearchHandler): | |
def get(self, keywords, related_id): | |
self.search_videos(keywords, related_id=related_id) | |
class VideoSearchHandlerWithRegion(VideoSearchHandler): | |
def get(self, keywords, regionCode): | |
self.search_videos(keywords, regionCode=regionCode.upper()) | |
app = webapp2.WSGIApplication([ | |
('/videos/([^/]+)/?', SimpleVideoSearchHandler), | |
('/videos/([^/]+)/countries/([^/]+)/?', VideoSearchHandlerWithRegion), | |
('/videos/([^/]+)/related/([^/]+)/?', RelatedVideoSearchHandler) | |
], debug=True) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment