Skip to content

Instantly share code, notes, and snippets.

@mlarocca
Last active August 29, 2015 13:57
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mlarocca/6717b49df8ca39410cb7 to your computer and use it in GitHub Desktop.
Save mlarocca/6717b49df8ca39410cb7 to your computer and use it in GitHub Desktop.
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"
#!/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)
#!/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