Mercurial > public > bravenewsurf
changeset 67:a878a98292a8
Merging new front page design from experimental UI branch.
author | Chris Ridgway <ckridgway@gmail.com> |
---|---|
date | Sun, 20 Nov 2011 22:59:06 -0600 |
parents | aaac975df679 (diff) ee1a90652c1e (current diff) |
children | 1d50a0db4f21 |
files | bns_website/static/css/base.css bns_website/templates/home.html |
diffstat | 18 files changed, 306 insertions(+), 32 deletions(-) [+] |
line wrap: on
line diff
--- a/.hgignore Thu Nov 17 22:11:38 2011 -0600 +++ b/.hgignore Sun Nov 20 22:59:06 2011 -0600 @@ -3,4 +3,5 @@ *.pyc *.swp secrets.json -*.db \ No newline at end of file +*.db +*.mp3
--- a/bns_website/core/tests/view_tests.py Thu Nov 17 22:11:38 2011 -0600 +++ b/bns_website/core/tests/view_tests.py Sun Nov 20 22:59:06 2011 -0600 @@ -26,15 +26,6 @@ self.assertEqual(response.status_code, 200) self.assertTemplateUsed(response, 'music.html') - def test_video(self): - """ - Tests the video page to ensure it displays without errors. - - """ - response = self.client.get(reverse('videos')) - self.assertEqual(response.status_code, 200) - self.assertTemplateUsed(response, 'videos.html') - def test_buy(self): """ Tests the buy page to ensure it displays without errors.
--- a/bns_website/settings/base.py Thu Nov 17 22:11:38 2011 -0600 +++ b/bns_website/settings/base.py Sun Nov 20 22:59:06 2011 -0600 @@ -128,6 +128,7 @@ 'bands', 'news', 'reviews', + 'videos', ] # A sample logging configuration. The only tangible logging
--- a/bns_website/static/css/base.css Thu Nov 17 22:11:38 2011 -0600 +++ b/bns_website/static/css/base.css Sun Nov 20 22:59:06 2011 -0600 @@ -1,5 +1,4 @@ body { - background: url('static/images/polonez_car.png'); padding-top: 60px } .social-sharing {
--- a/bns_website/static/css/bx_styles.css Thu Nov 17 22:11:38 2011 -0600 +++ b/bns_website/static/css/bx_styles.css Sun Nov 20 22:59:06 2011 -0600 @@ -31,10 +31,12 @@ .bx-pager a { margin-right: 5px; color: #fff; - padding: 3px 8px 3px 6px; + padding: 3px 7px 3px 7px; font-size: 12px; zoom:1; - background: url(../images/gray_pager.png) no-repeat 0 -20px; + background-color: #aaa; + -moz-border-radius: 20px; + -webkit-border-radius: 20px; } /*auto start button*/ @@ -63,7 +65,8 @@ /*pager links hover and active states*/ .bx-pager .pager-active, .bx-pager a:hover { - background-position: 0 0; + background-color: #666; + text-decoration: none; } /*pager wrapper*/
--- a/bns_website/templates/base.html Thu Nov 17 22:11:38 2011 -0600 +++ b/bns_website/templates/base.html Sun Nov 20 22:59:06 2011 -0600 @@ -8,7 +8,7 @@ <meta charset="utf-8" /> {% block custom_meta %}{% endblock %} <link rel="shortcut icon" href="{{ STATIC_URL }}images/favicon.ico" /> -<link rel="stylesheet" href="http://twitter.github.com/bootstrap/1.3.0/bootstrap.min.css" /> +<link rel="stylesheet" href="http://twitter.github.com/bootstrap/1.4.0/bootstrap.min.css" /> <link rel="stylesheet" href="{{ STATIC_URL }}css/base.css" /> {% block custom_css %}{% endblock %} {% block custom_js %}{% endblock %}
--- a/bns_website/templates/home.html Thu Nov 17 22:11:38 2011 -0600 +++ b/bns_website/templates/home.html Sun Nov 20 22:59:06 2011 -0600 @@ -107,7 +107,7 @@ <p><a href="{% url 'buy' %}" class="btn primary">Buy Now ยป</a></p> {% social_sharing 'Brave New Surf' 'http://bravenewsurf.com' %} </div> - <div class="span7"> + <div class="span6 offset1"> <div class="alert-message block-message info"> <h3>News</h3> {% list_news 5 %}
--- a/bns_website/templates/videos.html Thu Nov 17 22:11:38 2011 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,8 +0,0 @@ -{% extends 'base.html' %} -{% load core_tags %} -{% block title %}Watch{% endblock %} -{% block content %} -{% navbar 'videos' %} -<h1>Watch</h1> -<p><strong>TODO</strong>: embed some YouTube videos of the bands.</p> -{% endblock %}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bns_website/templates/videos/index.html Sun Nov 20 22:59:06 2011 -0600 @@ -0,0 +1,41 @@ +{% extends 'base.html' %} +{% load core_tags %} +{% block title %}Watch{% endblock %} +{% block content %} +{% navbar 'videos' %} +<h1>Watch</h1> + +{% if videos %} +<p> +Please enjoy this {{ videos|length }} video playlist of the bands that performed on the +<em>Brave New Surf</em> compilation. You can use the button that looks like a widescreen TV +at the bottom of the player to scroll through all the videos. +</p> +<div id="player"></div> + +<script> +var tag = document.createElement('script'); +tag.src = "http://www.youtube.com/player_api"; +var firstScriptTag = document.getElementsByTagName('script')[0]; +firstScriptTag.parentNode.insertBefore(tag, firstScriptTag); + +var player; +function onYouTubePlayerAPIReady() { + player = new YT.Player('player', { + videoId: '{{ videos|first }}', + {% if videos|length > 1 %} + playerVars: { playlist: [ + {% for video in videos|slice:"1:" %} + {% if not forloop.first %},{% endif %}'{{ video }}' + {% endfor %} ]}, + {% endif %} + width: '853', + height: '480' + }); +} +</script> + +{% else %} + <p>Videos of the bands are coming soon. Please check back later.</p> +{% endif %} +{% endblock %}
--- a/bns_website/urls.py Thu Nov 17 22:11:38 2011 -0600 +++ b/bns_website/urls.py Sun Nov 20 22:59:06 2011 -0600 @@ -25,17 +25,10 @@ url(r'^listen/$', TemplateView.as_view(template_name="music.html"), name="music"), - url(r'^watch/$', - TemplateView.as_view(template_name="videos.html"), - name="videos"), + url(r'^watch/$', include('videos.urls')), url(r'^buy/$', TemplateView.as_view(template_name="buy.html"), name="buy"), - - # Examples: - # url(r'^$', 'bns_website.views.home', name='home'), - # url(r'^bns_website/', include('bns_website.foo.urls')), - url(r'^admin/doc/', include('django.contrib.admindocs.urls')), url(r'^admin/', include(admin.site.urls)), )
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bns_website/videos/admin.py Sun Nov 20 22:59:06 2011 -0600 @@ -0,0 +1,95 @@ +""" +Automatic admin definitions for the videos application. + +""" +import datetime +import urlparse + +try: + from urlparse import parse_qs +except ImportError: + from cgi import parse_qs # for Python 2.5 + +from django.contrib import admin +from django.contrib import messages +from gdata.youtube.service import YouTubeService + +from videos.models import Playlist + + +class PlaylistAdmin(admin.ModelAdmin): + list_display = ['__unicode__', 'playlist_url', 'sync_date'] + readonly_fields = ['playlist_title', 'video_list', 'sync_date'] + actions = ['sync'] + + def sync(self, request, queryset): + for playlist in queryset: + self.sync_playlist(request, playlist) + + sync.short_description = 'Synchronize with YouTube' + + def sync_playlist(self, request, playlist): + """ + Retrieve the title and list of videos for a + YouTube playlist. + + """ + # Find the playlist ID: + parts = urlparse.urlparse(playlist.playlist_url) + query = parse_qs(parts.query) + if 'list' not in query: + messages.error(request, 'Invalid playlist %s' % + playlist.playlist_url) + return + + playlist_id = query['list'][0] + if not playlist_id.startswith('PL'): + messages.error(request, 'Invalid playlist ID in %s' % + playlist.playlist_url) + return + playlist_id = playlist_id[2:] + + # Get the playlist feed: + yt = YouTubeService() + feed = yt.GetYouTubePlaylistVideoFeed(playlist_id=playlist_id) + feed_title = feed.title.text + expected_count = int(feed.total_results.text) + + # Get all the videos in the feed; this may take multiple requests: + vids = [] + while True: + vids.extend(feed.entry) + next_link = feed.GetNextLink() + if not next_link: + break + feed = yt.Query(next_link.href) + + if len(vids) != expected_count: + messages.error(request, "%s: expected %d videos, got %d" % + (playlist.playlist_url, expected_count, len(vids))) + + # Find the video ID for each video + + vid_ids = [] + for vid in vids: + for link in vid.link: + parts = urlparse.urlparse(link.href) + query = parse_qs(parts.query) + if 'v' in query: + vid_ids.append(query['v'][0]) + break + else: + messages.error(request, "%s: video id not found for %s" % + (playlist.playlist_url, vid.title.text)) + + # Okay, save what we got + playlist.playlist_title = feed_title + playlist.video_list = ",".join(vid_ids) + playlist.sync_date = datetime.datetime.now() + playlist.save() + + messages.info(request, "Synchronized %s (%s)" % (feed_title, + playlist.playlist_url)) + + +admin.site.register(Playlist, PlaylistAdmin)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bns_website/videos/fixtures/playlist.json Sun Nov 20 22:59:06 2011 -0600 @@ -0,0 +1,12 @@ +[ + { + "pk": 1, + "model": "videos.playlist", + "fields": { + "playlist_url": "http://www.youtube.com/playlist?list=PL26E22C14D94D323F", + "sync_date": "2011-11-19 12:28:01", + "video_list": "jTJE2PDKkLM,RsWH6Hvk0ec,mBj3BKwyF50,xDYT0Vu0Xrk,XiNjzIBLwSE,kG626uATPcM,J618hE-GUXY,MKU8mgMwkyY,0LGUqEZcjtU,HACgijBE0JM,NFKwh967CQg,l2mTHH1WEFY,e_y6qWBkZvA,d_WvX06VNKU,sAItSEypYrA,ZfcXla0Rppc,HugPW5XZWQ4,PNkxPAReT5I,env8hOFFn44,_mDxMVQy3UY,u5gDyFMluio,sGDm3Wx2hNQ,am59GF0Dc3s,-JKKZaTSEAk,KUzsXvHVTjU,8b1r7t4LT1g,SXtr1u6Yizw,OxunllVGQQo,YJNzGRvI_kU,IFnyaCPyJSk,hIEGYQjkn0I,i9J0-OQkfRc,F8H8w0cLSS8,yxqC67op4gc,EQok0Jsi85k,p5R3HOv5S5k,RiHOgdLjD7g,CHGeikLt-bc,cVBm-XljTuM,Pt3lStrELhc,HgT8LJvdbL0,HACgijBE0JM,QKG0Fu8o7-w,z6bwirjUTTI,JwgfzvNyHoU,R7FEfqy1Xg8,i9J0-OQkfRc,2EI1JVoajBw,oASw2F86koo,chK776zOK-M", + "playlist_title": "Brave New Surf Bands" + } + } +] \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bns_website/videos/models.py Sun Nov 20 22:59:06 2011 -0600 @@ -0,0 +1,38 @@ +""" +Models for the videos app. + +""" +from django.db import models + + +# The whole purpose of this application is to shuffle the videos in +# a YouTube playlist. +# +# We'd like to embed a video player to show videos from all the bands that +# participated in the compilation. So we create a YouTube playlist with a long +# list of videos. YouTube no longer offers a way to shuffle the playlist via +# the embed code. Instead we will use the YouTube Javascript API to accomplish +# this. However, the Javascript API works off of video IDs. So we now need +# a way to obtain all the video IDs from a YouTube playlist. This model +# stores the playlist URL and an admin function can be run to retrieve the +# video ID list via the Python GData YouTube API. The video list is also +# stored in this model. The view function can then read the video ID list, +# randomize it, and give it to the template to build the appropriate +# Javascript. + +class Playlist(models.Model): + """ + This model stores a YouTube playlist URL and a list of video IDs that + make up the playlist. + + """ + playlist_title = models.CharField(max_length=128, blank=True) + playlist_url = models.URLField() + video_list = models.TextField(blank=True) + sync_date = models.DateTimeField(null=True, blank=True) + + def __unicode__(self): + if self.playlist_title: + return self.playlist_title + + return u"(Please sync with YouTube to retrieve the videos)"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bns_website/videos/tests/__init__.py Sun Nov 20 22:59:06 2011 -0600 @@ -0,0 +1,1 @@ +from view_tests import *
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bns_website/videos/tests/view_tests.py Sun Nov 20 22:59:06 2011 -0600 @@ -0,0 +1,33 @@ +""" +View tests for the videos application. + +""" +from django.test import TestCase +from django.core.urlresolvers import reverse + + +class NoVideosTest(TestCase): + + def test_index(self): + """ + Test that the page displays without any videos in the database. + + """ + response = self.client.get(reverse('videos')) + self.assertEqual(response.status_code, 200) + self.assertEqual(len(response.context['videos']), 0) + self.assertTemplateUsed(response, 'videos/index.html') + + +class SomeVideosTest(TestCase): + fixtures = ['playlist.json'] + + def test_index(self): + """ + Test that the page displays with videos in the database. + + """ + response = self.client.get(reverse('videos')) + self.assertEqual(response.status_code, 200) + self.assertEqual(len(response.context['videos']), 50) + self.assertTemplateUsed(response, 'videos/index.html')
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bns_website/videos/urls.py Sun Nov 20 22:59:06 2011 -0600 @@ -0,0 +1,9 @@ +""" +URLs for the videos application. + +""" +from django.conf.urls.defaults import * + +urlpatterns = patterns('videos.views', + url(r'^$', 'index', name='videos'), +)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bns_website/videos/views.py Sun Nov 20 22:59:06 2011 -0600 @@ -0,0 +1,20 @@ +""" +Views for the videos application. + +""" +import random +from django.shortcuts import render +from videos.models import Playlist + + +def index(request): + qs = Playlist.objects.all() + videos = [] + for playlist in qs: + videos.extend(playlist.video_list.split(',')) + + random.shuffle(videos) + + return render(request, 'videos/index.html', { + 'videos': videos, + })
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/get_vids.py Sun Nov 20 22:59:06 2011 -0600 @@ -0,0 +1,45 @@ +""" +Quick & dirty Python script to retrieve the video IDs of all the videos in a +playlist on YouTube. + +""" +import urlparse + +from gdata.youtube.service import YouTubeService + + +PLAYLIST_ID = '26E22C14D94D323F' + +yt = YouTubeService() +feed = yt.GetYouTubePlaylistVideoFeed(playlist_id=PLAYLIST_ID) + +print "Feed contains %s videos" % feed.total_results.text + +vids = [] +while True: + vids.extend(feed.entry) + next_link = feed.GetNextLink() + if not next_link: + break + feed = yt.Query(next_link.href) + +print "Got %d videos" % len(vids) + +vid_ids = [] +problems = [] +for vid in vids: + for link in vid.link: + url_data = urlparse.urlparse(link.href) + query = urlparse.parse_qs(url_data.query) + if 'v' in query: + vid_ids.append(query['v'][0]) + break + else: + print "Video id not found for %s" % vid.title.text + +video_id = vid_ids[0] +playlist = vid_ids[1:] + +print "videoId: '%s'," % video_id +print "playerVars: { playlist: [ %s ] }," % ','.join("'%s'" % v for v in + playlist)