Tip:
Highlight text to annotate it
X
[MUSIC PLAYING]
MALE SPEAKER: Shanghai GDG is a very
interesting developer community.
FEMALE SPEAKER: I'm glad somebody
has asked this question.
MALE SPEAKER: This is where the magic happens.
FEMALE SPEAKER: This is primarily a question and
answer show.
So if any of you out there would like to ask questions--
JJ BEHRENS: Howdy.
Welcome to Google Developers Live.
Today we're talking about YouTube API.
And we have Jeffrey Posnick with us over in Hangouts.
JEFFREY POSNICK: Hi, guys.
JJ BEHRENS: Howdy.
And we have Danny Hermes from the Google App Engine team.
Give it up, Danny.
Aw!
So today we're going to talk about Party Playlist Picker.
And when I first came to Google, before Google+ was
launched, we wanted to build something that integrated the
YouTube APIs with Google+.
And so Jeffrey Posnick and I decided that we should build
something cool, a nice mashup on Google App Engine in
Python, mashing up the YouTube APIs with the Google+ APIs.
DANNY HERMES: All the things I like to hear.
JJ BEHRENS: I know, isn't it?
Yeah, it was pretty sweet.
And I'm definitely in my comfort zone in Python.
DANNY HERMES: Sure.
JEFFREY POSNICK: It was a mega mashup.
JJ BEHRENS: Mega mashup.
And then it's like I kept on going to all these different
hackathons.
And I was like, oh, HTML5 hackathon?
I could do that.
So yeah, we had a great time coding it.
And so today we're going to talk about the app.
We're going to talk a little bit about what it does, how it
does it, how it works with Google App Engine.
Danny's going to tell us we suck.
DANNY HERMES: That's why I'm here.
JJ BEHRENS: He was like, dude, what are you doing?
There's so many better ways to do that.
And then we're going to peek at the code.
And so it's going to be a good time.
So, Jeffrey, you want to start us off, show us
what the app can do?
JEFFREY POSNICK: Sure thing, OK.
First of all, what I wanted to make clear is that what JJ and
I worked on is an open-source project, and the code is
freely available for folks to use.
We have a link to the source code on a blog post that we
have up announcing Party Playlist Picker.
So if you go to apiblog.youtube.com,
you can find that.
And I also wanted to make it clear that this project is
something that's separate from the official YouTube Google+
Hangout app, and that Hangout app has some similar features.
But what we're talking about today and what we're showing
off is something completely separate.
So please don't confuse the two.
JJ BEHRENS: And I would say we came up with the idea first.
JEFFREY POSNICK: I am not raising that
point, but fair enough.
Yeah, and as JJ mentioned, we had a really good time coding
this and did a lot of stuff via collaborative--
I guess, actually VNC pair programming coast to coast.
JJ BEHRENS: Yeah.
That was kind of crazy.
You're in New York.
I'm in San Francisco.
We were working two hours a day coding
this in our 20% time.
And we didn't do any of this in person.
We did this completely over Google Hangouts
with stuff like that.
At some point, we were doing screen sharing.
At some point, I was logged in to your machine, and we were
editing at the same--
pair programming remotely worked out really well.
DANNY HERMES: Wow.
JEFFREY POSNICK: Yeah, you were sending emails for me.
You were taking care of my work while I
wasn't paying attention.
And I appreciated that.
JJ BEHRENS: Yeah, this is not true.
JEFFREY POSNICK: That being said, this is
the fruits of labor.
So hopefully, you guys can see the screen that I'm
sharing right now.
Both JJ and I are engineers, I guess, first and
UI designers second.
So please pardon the spartan user interface.
JJ BEHRENS: What are you trying to say about my design
skills, Jeffrey?
DANNY HERMES: I've seen them.
I'll agree.
JEFFREY POSNICK: I'm trying to say Helvetica is classic.
There's nothing wrong with that.
So let's show off the way the actual app goes and then run
through some of features.
Then we'll talk more about how we built it, after folks have
had a chance to try it out.
So as all good YouTube API and Google API integrations go,
this starts with OAuth 2 login flow.
I think the way I'm sharing my screen, you might have a
little trouble seeing the actual window that's going to
appear when click on Login.
Or no, OK.
You can see that.
So I'm going to log in.
That's my account.
And I'm going to enter my two-step verification code as
all people should do.
I'm signed up for that.
And I'm going to be asked whether I would like to grant
access to Party Playlist Picker to manage my YouTube
account and know who I am on Google.
So this is an example of using two OAuth 2.0 scopes at once
to access my YouTube API data and access some
Google+ data as well.
And I do trust Party Playlist Picker, so I
will click Allow Access.
And after this login step, I'll be redirected back to
this, again, somewhat spartan but functional screen.
And at this point, I see a list of all the playlists.
And these are real YouTube playlists on the back end.
These are playlists I've created using
Party Playlist Picker.
So a little bit earlier, I created My New Playlist.
But I'm going to walk you through the whole flow of
creating a new playlist from scratch.
So in this case, enter Name.
Developers Live, So I'm going to Create a new playlist, and
that's the first step in the flow of using the app.
And I'm taken to this screen.
I am the only Partygoer right now, which is kind of the
story my life.
But I'm going to make it look a little bit more interesting.
I'll invite JJ and Danny to collaboratively edit this
playlist along with me.
So we're just making it so the standard Google+
Share button here.
And I'm going to--
"Hey, guys.
Want to join the party?" So the idea might be I'm going to
have some party or some sort of gathering later and have a
bunch of people attending.
And I'd like people to be able to create a playlist of videos
that they want to show during the party.
That's the basic idea.
So I'm going to add JJ.
I'm going to Daniel Hermes.
And I'm going to click Share.
So what this is doing is actually creating a post in
their Google+ streams.
And it has link-back to a unique URL that allows them to
come in and edit that shared playlist.
So that's the type of ACL that we're using in this case.
Anybody who has that URL could come in and
edit that shared playlist.
So hopefully, JJ and Danny saw that and will
get a chance to join.
In the meantime, I'm going to start adding some videos.
So we have a nice little search box there.
And this all is making YouTube API calls on the back end
using the standard YouTube API Python library.
So I see Shannon and JJ Behrens just joined.
If I want to know a little bit more about him, I think I can
click on that and go to his Google+ profile.
So we're integrated with Google+ in terms of getting
profile information and also sharing.
That's our vector for sharing things.
So I'm going to add a couple of videos.
I always like videos that have me in the
thumbnail, as that one does.
So I'm going to add that.
We have a little bit a jQuery UI, or maybe that's just
standard jQuery magic there for doing some of those
transitions.
And sometimes you might not be quite as familiar with some of
these videos that show up in the search results.
So we have a way of previewing the video right inline by
clicking on the Play button.
This uses the standard YouTube iFrame embed.
It just gives you an example of what kind of--
ooh!
Oh no!
So you might have just missed that.
But JJ just added a video to the playlist.
JJ is now actually in the Dart world.
He's transitioned off of YouTube.
So I think he's competing with me a little bit and tying to
add some Dart videos.
And there's another one.
So I'm going to say, all right, that's fine.
I'm going to actually be generous.
I'm going to move JJ's Dart video to the top of the
playlist here because I do want to see the "Introduction
to Dart."
DANNY HERMES: What kind of party is this with no music?
JJ BEHRENS: I know.
We're getting there.
We're getting there.
JEFFREY POSNICK: Yeah.
And we want to be careful about what we're broadcasting
over the Hangout also.
I think that Seth is going to be fine with us showing him
talking about Dart in the Hangout
right now, for instance.
So I don't anticipate too much of a problem with that.
So OK.
So this gives you an idea of how people collaboratively
edit playlists.
And if you've noticed, what happened is that when JJ added
a video to the playlist, without my page having to
refresh or anything, it just seamlessly appeared in the
list of the videos that are there.
So we're actually using the channels they've got-- which
Danny's going to talk a little bit about later--
to open a connection to the server and to just have the
server effectively push those updates down to us.
And we're doing something kind of nifty with the HTML that we
get pushed from the server and doing a diff using a
JavaScript diff library and trying to identify what the
new videos are.
So we're not getting the deltas from the server.
We're actually getting that whole chunk of HTML compared
to our local chunk of HTML.
And anything that the diff algorithm tells us is new, we
animate Showing.
JJ BEHRENS: I like the diff functionality.
Did you also show the drag-and-drop functionality?
JEFFREY POSNICK: Yeah, so we have drag and drop for
reordering.
We also have drag and drop for just adding
things to the playlist.
And that's going to end up--
I think somebody might have removed something from the
playlist in the meantime.
JJ BEHRENS: Yeah, I did.
JEFFREY POSNICK: Yeah, so can see the things getting
updated as we go.
So we have a nice little playlist now.
The type of parties that I throw, we normally just
discuss the YouTube API.
I don't know how the audience is going to necessarily react
to the Dart video at the end.
But we have about an hour plus of the
YouTube API concept there.
So I think people are probably going to be zonked out at that
point and not really notice that we're sneaking in 50
minutes of JJ talking about Dart in Glasgow.
JJ BEHRENS: And now we're going to talk about AS3!
JEFFREY POSNICK: Ooh!
That's always interesting.
So once the playlist is fully assembled, you could view the
playlist on YouTube.
You could see those videos are now in a
real YouTube playlist.
You could play them from here.
You could share the playlist.
You could get the embed code from the playlist straight
from YouTube.
So you're ready for your party.
And that's the basic idea.
JJ BEHRENS: You could also watch individual
videos on the site.
So that was a nice little light-box effect
that you did for that.
JEFFREY POSNICK: Yep, just right over there.
JJ BEHRENS: Yep.
That's pretty cool.
JEFFREY POSNICK: So if you're looking for examples of doing
that exact thing, for instance, where you have a
thumbnail for videos--
So this is just a thumbnail and has a little bit of
JavaScript and CSS to put that Play button over there.
If you're looking for an example of how to do that,
feel free to take our code.
JJ BEHRENS: I'm going to go offline to show you what it
looks like when someone has edited it in the
past but goes offline.
So we've got state going on there.
JEFFREY POSNICK: Yep.
So you keep track of who's currently editing and
everybody who's edited in the past.
Yeah, JJ, anything else major about
the app that I neglected?
I guess the Manage Playlists page.
That's just having the initial page over there where we could
go and choose different playlists.
JJ BEHRENS: No.
I think you got it.
Yeah.
JEFFREY POSNICK: Cool.
JJ BEHRENS: That's cool.
JEFFREY POSNICK: Yeah.
So as we mentioned, this is built on top
of Python App Engine.
And we have Danny in the studio, who is very much an
App Engine expert.
And I think you wanted to talk a little bit about some of the
sort of technology that we used and some more general
Python App Engine technology and how you can integrate with
other Google APIs.
JJ BEHRENS: Yeah.
So why don't we have a talk with Danny.
And Danny can tell us where we're doing it wrong.
And then we'll show some code.
DANNY HERMES: So in addition to being on the App Engine
team, I've also worked a lot on the
Google API client libraries.
When we're talking about Python, there are two
libraries that are the main ones.
We have the GData Python client.
And we have the Google API Python client.
And these libraries are actually targeting different
families of APIs.
So Google APIs that are a bit older, including the YouTube
API, were based on a GData standard, which was a Google
Data standard.
JJ BEHRENS: We're keeping it old school.
DANNY HERMES: We're keeping it old school.
And this newer library targets some newer discovery-based
APIs that Google offers, APIs that have an entire JSON
discovery document that totally explains
what that API does.
JJ BEHRENS: And that's what we're switching to right now.
We first announced that at Google I/O. And so we've got
some support, and we're working on more.
DANNY HERMES: Certainly.
So the reason I bring up these two libraries is because both
of them are actually being used in this application.
This is one of these things that I scolded JJ about.
So OAuth 2 is a relatively new spec, right?
JJ BEHRENS: Yeah.
DANNY HERMES: So we've had specs as a moving target as we
understand security and try to refine the model better for
usability for end users.
So when they originally wrote it, there was no OAuth 2
support in the GData Python Client Library.
But since the YouTube API is a GData API, they needed to use
the GData API.
So they do the OAuth 2 stuff with the Google API Python
client and the actual API calls with the
GData Python client.
JJ BEHRENS: We like it both ways.
DANNY HERMES: So a few things I want to say.
One, with the Google API Python client,
there are nice things.
If you're familiar with Python, there's a concept of a
decorator, which you put above a function or a method
declaration.
And it wraps the method, essentially redefining that
method, and so doing, actually gives it more functionality.
So the Google API Python Client Library gives a
decorator, which allows you to define a
simple response handler.
So if your web page that you're visiting has a Get
request handler, you can actually wrap their handler,
and it'll handle all the Auth stuff that you need to do.
And you don't really have to worry about it.
JJ BEHRENS: That is a big win.
That was a huge savings in terms of
making our life easier.
Because all that OAuth 2 token management stuff, it's like it
took care of it for us.
It automatically managed the tokens in the datastore.
And there was a little bit of work that we had to do.
But by and large, the decorator saved our bacon.
DANNY HERMES: Yup.
And that decorator, I will honestly say it's probably
easier to use than the OAuth 2 support in the
GData Python client.
But if you're looking to integrate a GData YouTube
application, there is OAuth 2 support in that library.
There was a blog post last November, actually, from Alain
Vongsouvanh on the Google Apps team.
And we'll try to provide a link in the description of
this YouTube video to that blog post.
But it describes the general flow.
You set up with a credentials object.
You get a URL to direct your users to, to actually accept
your app to have permissions to access their data, and then
they get redirected back to your application.
And from there, the actual credentials object is either
deserialized from some datastore or maybe
deserialized within memory, depending on what type of
application you're writing.
And you can actually finish the authorization flow.
And a lot of the actual details of the spec are
abstracted away from you by the library.
JJ BEHRENS: Yeah.
So I should just mention a little bit more since we're a
little bit down in the weeds.
From a high-level perspective, the goal is we have this
playlist on YouTube, and we want to manage the playlist
via this third-party application.
And so OAuth 2 is what makes it possible for me to use this
application and manage someone else's playlist.
DANNY HERMES: Sure.
And not only that, it also allows you to retrieve video
data, retrieve these thumbnails and the
descriptions, the titles, and these other things.
You're able, with the API, to get the data that you'd expect
to be able to get when you actually go to youtube.com.
JJ BEHRENS: So there's something clever going on here
that maybe you might not have thought about.
And that's that Jeffrey was the one
who created the playlist.
And yet I'm using my computer to manage his playlist.
And if know the YouTube API well enough, that is not
something the YouTube API gives you.
It doesn't give you the ability to manage other
people's playlists.
I bet you're wondering how we did that.
DANNY HERMES: "Clever" is one word.
"Trustworthy" may be another word.
But that's maybe all I'll say about that.
JJ BEHRENS: I should explain it, though.
The way it works is when Jeffrey--
Jeffrey logs in and gives the application access to his
OAuth 2 tokens.
And then when I'm managing his playlist, the application does
things to his playlist on my behalf.
And so it is safe insofar as the app itself is safe.
And of course, you're trusting the app.
I mean, that's what OAuth 2 is about, is saying this app is
trustworthy.
And so it just so happens that I'm the one initiating actions
to Jeffrey's playlist, which is kind of a neat idea.
JEFFREY POSNICK: And we are using a unique URL to control
access to folks who have access to this, which is not
necessarily the best approach.
It was the most workable approach that JJ and I found
that allowed us to integrate with Google+ the
way we wanted to.
DANNY HERMES: Sure.
And people who are maybe interested in a more robust
approach may consider, rather than having somebody else
controlling the owner's account, maybe having some
third-party account.
I don't know if the terms of service of YouTube allow this.
But it is another model rather than having some owner have a
decentralized place where playlists are owned.
But anyway, moving on from that, I want to talk about two
other App Engine features that were used.
Maybe two and a half, let's say.
The first is the Channel API, not the Channels API, as both
Jeff and JJ constantly say.
But the Channel API allows you to create
channels for message passing.
It's effectively a nice wrapper that creates a one-way
socket between your client that is actually accessing the
application via the web and the application itself.
JJ BEHRENS: Can we just call this "real time"?
DANNY HERMES: No.
We're going to call it the Channel API, which
is the name of it.
And so that unique URL that Jeff was talking about
actually gives the data about the channel
itself for the client.
And so a few things that you're able to do, so one, in
order to use it-- it's really simple--
there is--
in the very top of the head section of the HTML for the
page, there is a bit of JavaScript that comes
pre-loaded with the application that handles all
the code that you need and puts it in
the global name space.
JJ BEHRENS: It's way simpler than when I tried to do it
myself using Erlang.
I'll say that.
DANNY HERMES: Yeah, I'm going to guess anything with App
Engine is probably simpler than Erlang, but maybe not.
And once you have this code loaded, you actually open a
channel between the client and the application to pass
messages and receive messages.
And you just need to define a few handlers on it.
So you define a handler for it if an error occurs, if a
socket opens, if a socket closes, and then, of course,
if a message gets passed from the application.
And I mentioned it's a one-way channel.
So there's no way via this channel to send messages back
to the application.
However, since it's a web application, via Ajax, post
messages, and other things, you can still send messages to
the application.
And you can still--
via some form of identity that you have with your users, you
can still take that identity, and then whatever they do in
that post handler send the diff or send the full payload
of that playlist back to your users.
And that's what's actually happening.
JJ BEHRENS: Yeah, so we're using this in
two different places.
One is we're using this to keep track of who's currently
editing the web page.
So you could see who all the other partygoers are.
And the second thing is we're using this to show you the
updates to the playlist in real time.
And I would have to say since I've coded web stuff in
everything you could imagine from AS3 to .net, like weird
stuff, this is the easiest way that I've ever seen for doing
real-time comment type stuff.
It really pays off using App Engine to just have this stuff
work without having to architect it from scratch.
DANNY HERMES: I would certainly agree with that.
JJ BEHRENS: You should.
You're on the App Engine team.
JEFFREY POSNICK: Yes.
I just want to point one thing out.
We are guilty of using it maybe not entirely as it was
intended in that we're using it as a broadcast mechanism
for a bunch of different users,
potentially a lot of them.
DANNY HERMES: That's certainly how it was intended.
JEFFREY POSNICK: OK.
I just want to make sure because I got into some
discussions with some of the App Engine team members, not
you necessarily, but some other folks, about wanting to
have one API call to send messages to 50 people at once.
And I gathered that that was not entirely according to spec
to do that.
DANNY HERMES: Yeah, 50 might be a lot.
But certainly the intent is to be able to use it, to be able
to have some sense of collaboration, like playing
tic-tac-toe is the seminal example in the documentation.
JJ BEHRENS: So are you trying to say that this is sufficient
for my-sized parties, but maybe not for
Shakira-sized parties.
DANNY HERMES: Maybe.
Maybe we stop at Shakira.
So the last one, one and a half features of App Engine I
want to talk about, I want to give a bit of a preamble about
what App Engine.
So for people who don't know, it's a platform as a service.
And what this means on the surface is that you don't
actually have control of the system running it or even a
virtual machine.
It's even higher level than a virtual machine.
And you upload application code according to some
specification in some libraries that are included.
And you run your code from there.
So it's like I said, it's even higher level
than a virtual machine.
However there's still a concept of memory.
You still have local memory.
And you still have persistent disk.
And they're not really the same thing, RAM versus hard
drive, right?
JJ BEHRENS: Yep.
DANNY HERMES: And so with that in mind, I want to talk about
the ways this application is persisting data or maybe not
persisting data.
So some of the things like the actual identifier for the
channels to send messages, well, you could imagine you'd
have two users who don't know anything about each other and
haven't invited each other, but they have some catchy
playlist name that they want to use.
So the playlist itself is not a global identifier.
So you need to have some other sort of global identifier.
So this application uses something called memcache.
And it's exactly what it sounds like.
It sort of adheres to a memcache spec, which is sort
of agnostic of App Engine.
And using memcache, you can actually partially persist
data in memory.
But it doesn't actually make it to persistent disk.
And so they're able to use memcache for things like
caching the randomized token or the randomized identifier
for the channels so that, like I said, if you have two
different groups of people, two different parties making
playlists with the same name, you don't have a collision so
that they're sending the wrong messages to the wrong clients.
JJ BEHRENS: And we're also using memcache to cache
Google+ responses for very short amounts of time.
I know they wouldn't want us to cache them for
long amounts of time.
But, for instance, we want to show the user's profile
picture on every single page load.
We don't want to make it a hit to the Google+ servers every
single page load.
And so we cache that for very short amounts of time.
DANNY HERMES: Right.
And memcache--
I don't know that you guys are doing this in your
application--
it does allow you to specify when you add something the
cache that you'd like to invalidate it after a certain
amount of time.
Just like with RAM, it's not guaranteed to be
there all the time.
That's why I say it's not persistent.
So it is something that sort of transient.
This is the word.
I'm stealing this from JJ from our discussion earlier.
You can expect it to be there maybe some
portion of the time.
But expecting something you put in memcache to be there
all the time is a bad way to design applications.
However, given things like many clients accessing the
same data, reading directly from memory rather than going
to some external datastore or some external persistent
memory actually reduces the amount of I/O and can greatly
reduce the amount of latency in your responses.
JJ BEHRENS: We don't like slow apps at Google.
That's just how we roll.
DANNY HERMES: And so the tiny half-feature I wanted to talk
about is that they're actually, I believe, storing
credentials that they don't even know they're doing.
But the decorator itself, this OAuth Decorator, stores
credentials in the datastore for Google App Engine.
And the datastore is a persistent datastore.
And calls to the datastore take sometimes much longer,
but certainly a little bit longer than calls to memcache.
And I'm not going to say much else, other than that
datastore is a NoSQL database.
You can define arbitrary objects in it.
JJ BEHRENS: The largest NoSQL database.
DANNY HERMES: Exactly.
The largest NoSQL database in the world.
JJ BEHRENS: We also store a couple other
things in the datastore.
We store the list of people who have
ever edited a playlist.
That doesn't go away.
We always remember who's edited a playlist.
We also keep track of our internal identifier for the
title for the playlist.
There's actually a few different metadata-type things
that we wrap around the playlist.
DANNY HERMES: Things that can't disappear if memcache
decides to crap out on you.
JJ BEHRENS: Yes, that's right.
And then, a lot of the most interesting pieces of data
aren't stored in App Engine at all.
But they're actually stored in YouTube via the YouTube API.
So the playlist itself lives in YouTube.
JEFFREY POSNICK: And I really like that model, where we
don't have to worry about keeping things in sync and
what the authoritative version is.
We know that whatever's in YouTube is the
authoritative version.
And that's what gets pushed down to
users who are connected.
And they are obviously really elegant algorithms for trying
to do that sort of thing.
We're taking more of a brute force approach, but it seems
to work for us.
JJ BEHRENS: I'm all about the brute force.
That way it doesn't mess up.
Jeffrey, do you have any other comments about our storing in
memcache versus Datastore versus YouTube?
JEFFREY POSNICK: Yeah, just to build on
something that Danny mentioned.
I really, really liked what the Google API Python Client
Library was doing with the decorator and automatically
persisting those OAuth 2 tokens
for us in the datastore.
OAuth 2 kind of gets a reputation as being something
that is complicated.
And I usually tell people, if you think OAuth 2 is
complicated, you never used OAuth 1, which has
its own set of issues.
But the client library from Python, in particular-- and I
know that our other languages have varying degrees of
support, as well.
But I really, really found it very easy integrating with
OAuth 2 in a Python App Engine application.
It couldn't have been simpler.
You don't have to worry about keeping track of even doing
the refreshes.
The client library handles the token refreshes for you, which
is amazing.
So a really great experience.
JJ BEHRENS: Yeah, I agree with all of that.
I should mention a little bit about testing.
We kind of whipped this out as a prototype.
And so we didn't actually write test in this.
We did code-review everything.
Everything's well documented.
Literally, we code-reviewed everything.
But we left out the testing.
But some of you might have seen, I did a tutorial for
Google I/O called "Using Ruby on Rails and YouTube APIs for
Building Educational Apps." And even though that's a Ruby
talk instead of a Python talk, one thing I really like about
the talk is I explain how to do full-on test-driven
development with web APIs.
How do you deal with an API that you might not fully
understand?
How can you possibly mock that out?
And especially towards the end of the video, I show how to,
within a debugger, make a request, get the response,
grab it, store it away, and then set up mocks so that the
next time you do that request from within your tests, you
get the same actual,
completely legitimate response.
And so you could do full-on test-driven development,
making the entire request, integration-type testing even
with the web API.
So I recommend that tutorial.
I was in it, so, of course, I recommend it.
DANNY HERMES: Certainly.
JJ BEHRENS: But I know that Jeffrey and I, we definitely
used those tricks where we were making requests, dumping
ourselves into a debugger, and then playing around, which is
a very Pythonic thing to do.
You're playing around with the data, getting a feel for it,
and then writing the code that you're going to write, but
inside the debugger, and then copying and pasting
that into the code.
That works really well.
JEFFREY POSNICK: Cool.
Yeah.
JJ BEHRENS: So anything else we could think of that we
implemented in this that was kind of interesting?
JEFFREY POSNICK: I don't know.
I think that it's just great that there's a decent body of
both JavaScript code using jQuery pretty heavily and
Python code for folks to look through.
It's all open source.
If you see something in the app that might be useful to
your own project, feel free to borrow.
JJ BEHRENS: Yeah.
All right.
So why don't we take a look at the code?
And since I promised to do that, let me do that briefly.
And I'm going to go to this Google Hangout.
And I'm going to share my screen.
Desktop, Share Selected, and OK.
Great.
So here's Party Playlist Picker.
This is on code.google.com/ p/party-playlist-picker.
And I'm going to browse the source.
So this is in Git.
We have a top-level Python package called playlistpicker.
We have a directory called static for all
of our static files.
And then we have a directory called third-party, for all of
our third-party Python libraries, such as apiclient,
atom, gdata, httplib2, oauth2client, and template.
DANNY HERMES: You might want to zoom in a bit.
JJ BEHRENS: Oop, thanks.
Thank you.
OK?
DANNY HERMES: There you go.
JJ BEHRENS: So in static, we have CSS images.
And we have this big chunk of jQuery code.
And it looks like jQuery code, a bunch of nested functions
and a bunch of the dollar sign.
DANNY HERMES: Callback hell.
JJ BEHRENS: Yeah, yeah.
And callbacks all over the place.
And we used--
what do you call the basic framework that App
Engine uses in Python?
It's App Client?
I forget the name of it.
What is this?
DANNY HERMES: App.yaml, the application configuration?
JJ BEHRENS: WebApp.
I'm sorry.
WebApp is the basic framework in Python.
DANNY HERMES: I see, yeah.
JJ BEHRENS: So this is a WebApp application.
It's not Django.
But we structured it in a way that would be very, very
familiar to Django programmers or Ruby on Rails programmers.
So inside this package, playlistpicker, we have
handlers, which handle a specific page.
We have templates.
And then we have utils.
And so each page generally has a handler.
Each page generally has a template.
And then the utils is a bunch of stuff for
all that other stuff.
We also have a routes file, where we import things.
This is a little bit brute force-ish.
But we map out all of our urls and all the handlers.
So that's pretty straightforward.
DANNY HERMES: Pretty Django.
JJ BEHRENS: Pretty Django-ish, except for we're not doing any
automatic stuff.
But that worked out all fine.
So in the utils directory, we created files for dealing with
channels, friendlist, googleplus, memcache,
web-related stuff and YouTube stuff.
And since this is a YouTube show, I should point out we
needed functions for creating YouTube service, preparing
playlists, parsing durations in seconds-- you know, you do
a little bit of random parsing when you're dealing with API--
writing a playlist, fetching a feed and
entries, and so forth.
And so all the YouTube-related stuff, it's in there.
You could look at it if you need to.
So let me jump over to the handlers.
We have handlers for all the different things like the
playlist handler, removing the playlist
entry, the search handler.
The Ajax is calling back to various handlers.
And just like Django and Ruby on Rails?
DANNY HERMES: Now, do you have a separate module for every
single handler?
JJ BEHRENS: I think sometimes we-- yeah.
Yeah, we do.
DANNY HERMES: Wow.
Wow.
JJ BEHRENS: Yeah.
I like to keep things a little bit small.
I don't know.
My brain's not overly large.
DANNY HERMES: For serving static content, though?
I mean--
JJ BEHRENS: For static content, it's
in the static directory.
DANNY HERMES: Oh, OK.
There you go.
No handler needed.
JJ BEHRENS: No handler needed.
All the handlers have a parent class, which is
in this base handler.
And this takes care of a bunch of interesting things.
Also, it sets up our decorator that you were talking about.
It takes care of a bunch of authentication-type stuff.
One interesting thing is that there's the GData API and then
the newer types of API.
And when you have an authorization error, they
throw different exceptions.
DANNY HERMES: Different status codes?
JJ BEHRENS: No, not different status codes.
But the libraries itself will throw a
different Python exception.
DANNY HERMES: Ah, I see.
I see.
JJ BEHRENS: And so we set up a global exception handler to
handle both of those and follow them through the same
place to take care of, for instance, if someone's OAuth 2
token is expired.
And so setting up a global exception handler is a really,
really useful thing to be able to do.
DANNY HERMES: Yeah.
And certainly, given the support in those both
libraries now for OAuth 2, you actually don't have to worry
about what or not a token's expired.
JJ BEHRENS: Yes, yes.
But setting up a global exception
handler comes in handy.
That is a tool that's reusable.
DANNY HERMES: Certainly.
JJ BEHRENS: So here's the editplaylisthandler.
It's pretty simple.
We have a Git.
We're making use of various of those util modules.
We're setting up some template parameters.
And then we're rendering a template.
Let me show you what a template looks like.
This is based on Django's templating system.
And it looks fairly straightforward.
If you've seen Django or if you've seen Ruby on Rails,
none of the stuff is all that unfamiliar.
There's one trick that we did where every template can add
to the JavaScript head.
That's kind of nice because I like having page-specific
JavaScript.
That's kind of nice.
And let me see.
I think I'm out of things to talk about.
There's the code.
If you're interested in looking at the code some more,
you could definitely download it.
DANNY HERMES: Now, did you guys use Python
2.5 or Python 2.7?
I think it was Python 2.5.
Yeah.
DANNY HERMES: OK.
JJ BEHRENS: This is before Python 2.7 support was around.
We actually worked on this for a surprisingly long time.
If you look at the code, it's not a tiny amount of code.
I mean, it's not massive.
But we worked on this for several quarters.
DANNY HERMES: Sure.
Certainly.
So a quick note.
There are two different Python runtimes that are supported in
App Engine.
And Python 2.5 was the very first runtime for App Engine.
There are four now, including both Python, Go, and Java.
And the Python 2.7 runtime does not use Django as the
default templating system.
JJ BEHRENS: Oh, is that right?
DANNY HERMES: But it's still possible to use Django.
But there's a bit of a difference there.
So for people who are used to Python 2.7, all this you're
hearing about Django, it's really the sort of
capabilities that came out of the box.
Django was chosen as an arbitrarily framework, which
was also easy to use.
But if there's anything Python has a lot of, it's frameworks.
JJ BEHRENS: Yeah.
I always say that to be a really good Python programmer,
you have to do, really, three things.
One is to write your own templating language.
Then you have to write your own framework.
And then you have to implement Scheme in Python.
I mean, those are the bars.
DANNY HERMES: Yeah.
I'm apparently zero out of three, a terrible Python
programmer.
JJ BEHRENS: Well, we're going to fix that later.
So I think we're--
Jeffrey, did you have anything else to add?
Did we lose Jeffrey?
I think we might have lost Jeffrey.
Oh, I'm supposed to mention the fact that not only is
Google hiring, but the YouTube API team in Developer
Relations is hiring.
It's a busy life, but it's a fun life.
DANNY HERMES: Oh, it's great life.
Developer Relations is probably the most fun
place in the world.
I would rather do this job than be president.
President looks just kind of stressful.
DANNY HERMES: Bar none, I would rather do
this than be president.
JJ BEHRENS: Agreed.
Yes, especially since I have horrible
skeletons in my closet.
Yes.
No, not really.
But anyway, thank you guys for watching today.
If you guys stuck around to the very end,
more kudos to you.
I think you guys are awesome .
And Danny, thanks a lot for coming around today and
telling me how much I suck in my app.
DANNY HERMES: My pleasure.
JJ BEHRENS: We will see you guys next time.
DANNY HERMES: Yeah, and check out the description on YouTube
for some helpful links.
JJ BEHRENS: Yep.
[MUSIC PLAYING]