# olpc-video.py : written in Python : www.python.org
# Google App Engine approach to YouTube Search, Player, and Playlists
# a separate player optimizes access and lowers load times for pages
# also allows a separate XO users' community and social data set
# datetime, users, and db are currently unused, but will be useful for community and social data
#from datetime import datetime
#from google.appengine.api import users
#from google.appengine.ext import db
import cgi
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.api.urlfetch import fetch, GET
# MainPage at /olpc-video/
class MainPage(webapp.RequestHandler):
def get(self):
self.response.out.write('''
Video for XO Laptop
''')
# Explaining how to get Adobe Flash working on the laptop
class Flash(webapp.RequestHandler):
def get(self):
self.response.out.write('''
Flash for XO
Adobe Flash for XO Laptop
You will need Adobe Flash to play YouTube videos on the XO laptop
- Connect to the Inernet and start the Terminal activity.
- Enter each of these commands (note -l is the letter l ):
- su -l
- wget http://fpdownload.macromedia.com/get/flashplayer/current/flash-plugin-10.0.15.3-release.i386.rpm
- rpm -i flash-plugin-10.0.15.3-release.i386.rpm
- exit
Instructions on OLPC Wiki
''')
# Explaining why olpc-video is better than using YouTube.com on the XO
class Separate(webapp.RequestHandler):
def get(self):
self.response.out.write('''
Why the XO Player?
Why have a separate player for the XO?
- The controls on YouTube.com are small and slow on the XO
- The official YouTube site loads related videos, comments, and other content - slowing down presentation
- OLPC-video has strict SafeSearch and does not show YouTube comments
- The OLPC-video player page fits perfectly onto the XO's screen: [pic]
- A separate rating database can be created for users of the XO
- A separate favorites/bookmarking system can be created for users of the XO
- Some YouTube videos fail to play on the XO. OLPC-video search filters out these videos.
''')
# Player is where videos are displayed
class Player(webapp.RequestHandler):
def get(self):
# print JavaScript (probably should be in a play.js or other file)
watchVid = cgi.escape(self.request.get('v'))
self.response.out.write('''
Video for XO Laptop
Videos for the XO Laptop
''')
# add &welcome=true to a player link to display this close-able About: banner
if(self.request.get('welcome') == 'true'):
self.response.out.write("");
#print HTML for player and icons. The Powered by YouTube image is requested for all uses of the YouTube API
self.response.out.write('''
''')
# Search page - power to filter and mark results as needed
class Search(webapp.RequestHandler):
def get(self):
term = cgi.escape(self.request.get("term"))
offset = self.request.get('offset')
# see a sample API feed: http://gdata.youtube.com/feeds/api/videos?q=Pittsburgh&max-results=30&safeSearch=strict&format=5&v=2
if(offset != ''):
VidResults = fetch('http://gdata.youtube.com/feeds/api/videos?q=' + term.replace(" ",",") + '&start-index=' + offset + '&max-results=30&safeSearch=strict&format=5&v=2', payload=None, method=GET, headers={}, allow_truncated=False, follow_redirects=True)
else:
VidResults = fetch('http://gdata.youtube.com/feeds/api/videos?q=' + term.replace(" ",",") + '&max-results=30&safeSearch=strict&format=5&v=2', payload=None, method=GET, headers={}, allow_truncated=False, follow_redirects=True)
vidData = VidResults.content
processedResults = ""
# check if no videos were found
if(vidData.find("totalResults>0") != -1):
processedResults = "There were no results on YouTube.
"
else:
# col == 0: left column of results ; col == 1 : right column of results
col = 0
while(vidData.find(" -1):
# extract video title
title = vidData[vidData.find(' 60):
# convert seconds to mm:ss
seconds = duration % 60
if(seconds > 9):
duration = str((duration - seconds) / 60) + ":" + str(seconds)
else:
duration = str((duration - seconds) / 60) + ":0" + str(seconds)
else:
if(duration > 9):
duration = "0:" + str(duration)
else:
duration = "0:0" + str(duration)
# extract YouTube video ID
player = vidData[vidData.find('") : len(player) ]
player = player[0 : player.find("'/>")]
# extract video thumbnail (small pic)
thumbnail = vidData[vidData.find('"
processedResults = processedResults + ' | ' + title + ' Length: ' + duration + ' | '
if(col == 1):
processedResults = processedResults + ""
col = 0
else:
col = 1
# filter follow-up: repeats search on two more pages looking for playable videos
if(processedResults.find('img') == -1):
if(offset >= 60):
processedResults = "No popular videos for your query (" + term + ") could run in the player.
UNDER CONSTRUCTION: My XO laptop has an odd audio echo on some videos, and I am experimenting with ways to keep these from appearing in search. I intend to test this and find a workable solution.
"
else:
offset = offset + 30
self.redirect('/olpc-video/search?term=' + term + '&offset=' + str(offset))
# print page with results
self.response.out.write('''
Search Results from YouTube
Videos for the XO Laptop
''' + processedResults + '''
''')
# Library section from OLPCMagongo's YouTube playlists
# TODO: check for more than 25 playlists, work out social data for library videos
class Library(webapp.RequestHandler):
def get(self):
# "shelf" is used instead of "playlist" - these videos are not played as a playlist
libraryShelf = self.request.get('shelf')
offset = self.request.get('offset')
if(libraryShelf == ''):
# no shelf selected; requesting the library homepage
shelfList = fetch('http://gdata.youtube.com/feeds/api/users/olpcmagongo/playlists', payload=None, method=GET, headers={}, allow_truncated=False, follow_redirects=True)
shelfData = shelfList.content
shelfData = shelfData[shelfData.find('') : len(shelfData)]
self.response.out.write('''
OLPC Video Library
OLPC Video Library
''')
processedResults = ""
while(shelfData.find('') != -1):
# extract information about each playlist
shelfTitle = shelfData[shelfData.find("")]
shelfDescription = shelfData[shelfData.find("")]
shelfID = shelfData[shelfData.find("") + 15 : len(shelfData)]
shelfData = shelfID[shelfID.find("") : len(shelfID)]
shelfID = shelfID[0 : shelfID.find("")]
# write the playlist information
processedResults = processedResults + ''
self.response.out.write(processedResults)
else:
# specific shelf requested - load this playlist's information
if(offset == ''):
vidList = fetch('http://gdata.youtube.com/feeds/api/playlists/' + cgi.escape(libraryShelf) + '?max-results=30', payload=None, method=GET, headers={}, allow_truncated=False, follow_redirects=True)
else:
vidList = fetch('http://gdata.youtube.com/feeds/api/playlists/' + cgi.escape(libraryShelf) + '?max-results=30&start-index=' + offset, payload=None, method=GET, headers={}, allow_truncated=False, follow_redirects=True)
vidData = vidList.content
shelfTitle = vidData[vidData.find('')]
self.response.out.write('''
OLPC Video Library - ''' + shelfTitle + '''
''')
vidData = vidData[vidData.find('') : len(vidData)]
# col == 0: left column of results ; col == 1 : right column of results
col = 0
vidCount = 0
processedResults = ""
# extract information about each video
while(vidData.find('') != -1):
# extract video title
title = vidData[vidData.find('') - 1])
if(duration > 60):
# convert seconds to mm:ss
seconds = duration % 60
if(seconds > 9):
duration = str((duration - seconds) / 60) + ":" + str(seconds)
else:
duration = str((duration - seconds) / 60) + ":0" + str(seconds)
else:
if(duration > 9):
duration = "0:" + str(duration)
else:
duration = "0:0" + str(duration)
# extract YouTube video ID
player = vidData[vidData.find('") : len(player) ]
player = player[0 : player.find("'/>")]
# infer video thumbnail (small pic)
thumbnail = "http://i.ytimg.com/vi/" + player[player.find('?v=') + 3 : len(player)] + "/2.jpg"
# print into the left or right column
if(col == 0):
processedResults = processedResults + ""
processedResults = processedResults + ' | ' + title + ' Length: ' + duration + '
| '
vidCount = vidCount + 1
if(col == 1):
processedResults = processedResults + "
"
col = 0
else:
col = 1
# have information, now print
if(vidCount % 2 == 1):
self.response.out.write("")
else:
self.response.out.write("")
if(vidCount == 30):
self.response.out.write('''
''')
# print YouTube API image and close page
self.response.out.write('''
''')
# TODO: make special ClassShare
class ClassShare(webapp.RequestHandler):
def get(self):
self.response.out.write(''' ''')
# NTV Kenya section - shows most recent videos from a Kenyan news channel
# TODO: add social data
class NTVKenya(webapp.RequestHandler):
def get(self):
offset = self.request.get('offset')
if(offset == ''):
vidList = fetch('http://gdata.youtube.com/feeds/api/users/ntvkenya/uploads?orderby=published&max-results=30', payload=None, method=GET, headers={}, allow_truncated=False, follow_redirects=True)
else:
vidList = fetch('http://gdata.youtube.com/feeds/api/users/ntvkenya/uploads?orderby=published&max-results=30&start-index=' + offset, payload=None, method=GET, headers={}, allow_truncated=False, follow_redirects=True)
vidData = vidList.content
self.response.out.write('''
NTV Kenya Videos
''')
vidData = vidData[vidData.find('') : len(vidData)]
# col == 0: left column of results ; col == 1 : right column of results
col = 0
vidCount = 0
processedResults = ""
# extract information about each video
while(vidData.find('') != -1):
# extract video title
title = vidData[vidData.find('') - 1])
if(duration > 60):
# convert seconds to mm:ss
seconds = duration % 60
if(seconds > 9):
duration = str((duration - seconds) / 60) + ":" + str(seconds)
else:
duration = str((duration - seconds) / 60) + ":0" + str(seconds)
else:
if(duration > 9):
duration = "0:" + str(duration)
else:
duration = "0:0" + str(duration)
# extract YouTube video ID
player = vidData[vidData.find('") : len(player) ]
player = player[0 : player.find("'/>")]
# infer video thumbnail (small pic)
thumbnail = "http://i.ytimg.com/vi/" + player[player.find('?v=') + 3 : len(player)] + "/2.jpg"
# print into the left or right column
if(col == 0):
processedResults = processedResults + ""
processedResults = processedResults + ' | ' + title + ' Length: ' + duration + '
| '
vidCount = vidCount + 1
if(col == 1):
processedResults = processedResults + "
"
col = 0
else:
col = 1
# have information, now print
if(vidCount % 2 == 1):
self.response.out.write("")
else:
self.response.out.write("")
# print the "Find More" link
self.response.out.write('''
''')
# print YouTube API image and close
self.response.out.write('''
''')
# core URL-sorting and other details
application = webapp.WSGIApplication(
[('/olpc-video/search.*', Search),
('/olpc-video/player.*', Player),
('/olpc-video/library.*', Library),
('/olpc-video/class.*', ClassShare),
('/olpc-video/NTV-Kenya', NTVKenya),
('/olpc-video/separate', Separate),
('/olpc-video/flash', Flash),
('/olpc-video.*', MainPage)],
debug=True)
def main():
run_wsgi_app(application)
if __name__ == "__main__":
main()