Youtube Together 6 — Room Functionality

(Originally posted July 22, 2013)

With the basic functionality finished in the last post, we need to address the obvious point in the room… the fact that this has all been all on one url. How are we supposed to share with people we want when everyone is on the same stream? To do this, we want to allow the person to create a “room” where they can share the code and let everyone input together.

We’re going to need to change a lot of things in to get this to work, but most of those changes are just refactoring of the code. But we have to start somewhere, so it might as well be with the models. Since we’re adding support for different rooms, we might as well make a model for a room. Besides linking to the url class, we also need to make a slight change to the url class itself so it knows that there is a link to a room. The resulting models.py will look like the following.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Room(db.Model):
  id = db.Column(db.Integer, primary_key=True)
  name = db.Column(db.String(50))
  urls = db.relationship('YTUrl', backref='room', lazy='dynamic')
  def __init__(self, name):
   self.name = name
  def __repr__(self):
    return self.name
class YTUrl(db.Model):
  id = db.Column(db.Integer, primary_key=True)
  url = db.Column(db.String(80))
  title = db.Column(db.String(40))
  video_key = db.Column(db.String(20))
  room_id = db.Column(db.Integer, db.ForeignKey('room.id'))
  def __init__(self, url, title, video_key, room_id):
    self.url = url
    self.title = title
    self.video_key = video_key
    self.room_id = room_id
  def __repr__(self):
    return self.title

This example was taken right from the SqlAlchemy example pages so you can refer to them if there’s any confusion. Now we want to take on changing of the routes. For the urls, we want to have each room at url.com/room/roomid where roomid is the id assigned to the room. What we want to do is shift the logic that we had at the index route to that url. We also have to update the gathering and processing of the video ids to reflect the new models. The resulting view, which is in views.py if you forgot, should look like the following.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
@app.route('/room/<rid>', methods=['GET''POST'])
def room(rid):
  room = Room.query.get(rid)
  if room is None:
    return abort(404)
  if request.method == 'POST':
    poss_url = request.form['youtube-url']
    parsed_url = urlparse.urlparse(poss_url)
    if parsed_url[1== YOUTUBE_URL:
      query_dict = cgi.parse_qs(parsed_url[4])
      try:
        video_key = query_dict['v'][0]
      except ValueError:
        #odd, but we need error checking. just ditch
        abort(500)
      data_url = YOUTUBE_DATA_URL + video_key + YOUTUBE_DATA_PARAMS_URL
      resp = requests.get(data_url)
      video_info_dict = resp.json()
      title = video_info_dict['entry']['title']['$t']
      url = YTUrl(poss_url, title, video_key, rid)
      db.session.add(url)
      db.session.commit()
      return jsonify(success=True)
    return jsonify(success=False#here we want to give errors...
  queue = room.urls
  return render_template('room.html', queue=queue, room=room)

The only things different are the database queries for the objects and the routing at the top. Note how we grab the info from the url in the second and third lines. I included the entire function so everyone can know what’s going on. The view for the update also needs to change to reflect the new models.

1
2
3
4
5
6
7
8
9
10
11
12
13
@app.route('/update/<rid>')
def update(rid):
  room = Room.query.get(rid)
  if room is None:
    return abort(404)
  queue = room.urls
  queue_list = []
  for in queue:
    info = {}
    info['title'= q.title
    info['key'= q.video_key
    queue_list.append(info)
  return jsonify(queue=queue_list)

This is very similar to the changes above. I should mention that we also need to change the urls in the javascript files, since they need to point to the correct /room/ urls. To do this, just put the room id somewhere in the html as an attribute and use jquery to extract it and concatinate that with the normal url. Here is an example of the new titles on the room pages.

1
<h1 id="room-info" rid="{{room.id}}">{{room.name}}</h1>

The last thing we have to worry about is the creation of the rooms. We are going to do this at the base url, so users know what to do at the beginning. The html for this view just needs to include a basic form where the user just inputs what they want to name their room. The view for this is also simple.

1
2
3
4
5
6
7
8
9
@app.route('/', methods=['GET''POST'])
def index():
  if request.method == 'POST':
    name = request.form['room-name']
    room = Room(name=name)
    db.session.add(room)
    db.session.commit()
    return redirect(url_for('room', rid=room.id))
  return render_template('index.html')

In the html, all you have to do is make sure that the input for the name has the attribute name=”room-name” so that you can get the value from request.form. Note that we redirect the user to the room when they create it. This first argument in url_for is the name of the function in views.py that we want to redirect to, and then we use keyword arguments after for the room’s id.

With this, we should now have the ability to create separate rooms for people to queue their music! With all the basic functionality done, we now need to clean up the presentation before we can call it a minimum viable product. Next post will be on that subject.

Leave a comment