Got live radio working

This commit is contained in:
Fergal Moran
2013-06-19 14:29:50 +01:00
parent c42bdd3b86
commit c6997ec845
24 changed files with 812 additions and 79 deletions

View File

@@ -6,8 +6,8 @@ com.podnoms.settings = {
REALTIME_HOST: 'www.deepsouthsounds.com:8081',
REALTIME_PORT: 'www.deepsouthsounds.com:8081',
urlRoot: '/api/v1/',
liveStreamRoot: 'http://radio.deepsouthsounds.com:8000/mp3',
streamInfoUrl: 'http://radio.deepsouthsounds.com:8000/mp3',
liveStreamRoot: 'http://rad.deepsouthsounds.com:8000/dss_320_mp3',
streamInfoUrl: 'http://rad.deepsouthsounds.com:8000/dss_320_mp3',
volume: '50',
smDebugMode: false,
isDebug: false,

0
manage.py Executable file → Normal file
View File

69
static/css/bootstrap-player.css vendored Normal file
View File

@@ -0,0 +1,69 @@
.playa input[type=range] {
-webkit-appearance:none;
-moz-apperance:none;
background-color:#ddd;
border: 1px solid #bbb;
height:.5em;
border-radius:.5em;
width:100%;
margin:-2px;
padding:0 !important;
line-height:0;
}
.playa input[type=range]::-webkit-slider-thumb {
-webkit-appearance:none;
-moz-apperance:none;
z-index:3;
height:1em;
width:1em;
border-radius:1em;
border:1px solid #aaa;
background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #fefefe), color-stop(0.49, #dddddd), color-stop(0.51, #d1d1d1), color-stop(1, #a1a1a1));
}
.playa {
/*margin:0;*/
}
.playa .thumbnail {
width:96%;
padding:1.5%;
}
.playa .btn-group {
text-align:center;
}
@media (max-width: 979px) and (min-width: 768px){
.span4 .playa, .playa.span4{
padding:0;
}
}
@media (min-width: 768px){
.playa .btn-group .btn {
padding:4px 3px;
margin:auto;
display:inline-block;
float:none;
}
.playa .btn-group .span1 {
width:8%;
}
.playa .btn-group .span2 {
width:16%;
}
.playa .btn-group .span3 {
width:25%;
}
.playa .btn-group .span4{
width:33%;
}
.playa.span2 .btn-group .btn, .playa.span1 .btn-group .btn, .span2 .playa .btn-group .btn, .span1 .playa .btn-group .btn{
width:100%;
display:block;
}
.span4.playa, .span3 .playa, .span2 .playa, .span1 .playa, .playa.span4, .playa.span3, .playa.span2, .playa.span1{
padding:0;
overflow:hidden;
}
}

BIN
static/img/radio.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

@@ -7,6 +7,8 @@ define ['app', 'marionette', 'vent', 'utils'],
@listenTo(vent, 'mix:init', @mixInit)
@listenTo(vent, 'mix:pause', @mixPause)
@listenTo(vent, 'mix:play', @mixPlay)
@listenTo(vent, 'live:play', @livePlay)
@listenTo(vent, 'live:pause', @livePause)
mixInit: (model) =>
console.log "AudioController: mixInit"
@@ -32,5 +34,13 @@ define ['app', 'marionette', 'vent', 'utils'],
mixPause: (model) ->
console.log("AudioController: mixPause")
com.podnoms.player.pause();
livePlay: ->
console.log("AudioController: livePlay")
com.podnoms.player.playLive
success: ->
console.log("Live stream started")
vent.trigger('live:started')
AudioController

View File

@@ -1,30 +1,33 @@
// Generated by CoffeeScript 1.3.3
// Generated by CoffeeScript 1.6.2
(function() {
var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
define(['app', 'marionette', 'vent', 'utils'], function(App, Marionette, vent, utils) {
var AudioController;
AudioController = (function(_super) {
var AudioController, _ref;
AudioController = (function(_super) {
__extends(AudioController, _super);
function AudioController() {
this.mixInit = __bind(this.mixInit, this);
return AudioController.__super__.constructor.apply(this, arguments);
this.mixInit = __bind(this.mixInit, this); _ref = AudioController.__super__.constructor.apply(this, arguments);
return _ref;
}
AudioController.prototype.initialize = function(options) {
console.log("AudioController: initialize");
this.listenTo(vent, 'mix:init', this.mixInit);
this.listenTo(vent, 'mix:pause', this.mixPause);
return this.listenTo(vent, 'mix:play', this.mixPlay);
this.listenTo(vent, 'mix:play', this.mixPlay);
this.listenTo(vent, 'live:play', this.livePlay);
return this.listenTo(vent, 'live:pause', this.livePause);
};
AudioController.prototype.mixInit = function(model) {
var id,
_this = this;
console.log("AudioController: mixInit");
id = model.get('id');
com.podnoms.player.stopPlaying();
@@ -53,6 +56,16 @@
return com.podnoms.player.pause();
};
AudioController.prototype.livePlay = function() {
console.log("AudioController: livePlay");
return com.podnoms.player.playLive({
success: function() {
console.log("Live stream started");
return vent.trigger('live:started');
}
});
};
return AudioController;
})(Marionette.Controller);

View File

@@ -1,12 +1,14 @@
// Generated by CoffeeScript 1.3.3
// Generated by CoffeeScript 1.6.2
(function() {
var __hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
define(['marionette'], function(Marionette) {
var PanningRegion, getPrefixedCssProp;
var PanningRegion, getPrefixedCssProp, _ref;
getPrefixedCssProp = function(baseProp) {
var str;
str = Modernizr.prefixed(baseProp);
str = str.replace(/([A-Z])/g, function(str, m1) {
return "-" + m1.toLowerCase();
@@ -14,17 +16,18 @@
return str;
};
PanningRegion = (function(_super) {
__extends(PanningRegion, _super);
function PanningRegion() {
return PanningRegion.__super__.constructor.apply(this, arguments);
_ref = PanningRegion.__super__.constructor.apply(this, arguments);
return _ref;
}
PanningRegion.prototype.el = "#content";
PanningRegion.prototype.initialize = function() {
var transEndEventNames;
transEndEventNames = {
WebkitTransition: "webkitTransitionEnd",
MozTransition: "transitionend",
@@ -40,6 +43,7 @@
PanningRegion.prototype.transitionToView = function(newView, type) {
var self, view;
self = this;
view = this.currentView;
if (!view || view.isClosed) {
@@ -49,6 +53,7 @@
Marionette.triggerMethod.call(this, "willTransition", view);
newView.on("render", function() {
var $background, newViewMatrix, translation, worldBgMatrix, worldContentMatrix;
self.$el.off(self.transEndEventName);
translation = void 0;
if (type === "slide") {

View File

@@ -1,8 +1,8 @@
// Generated by CoffeeScript 1.3.3
// Generated by CoffeeScript 1.6.2
(function() {
define(['jquery', 'bootstrap', 'toastr'], function($, bootstrap, toastr) {
var _this = this;
return {
modal: function(url) {
if (url) {
@@ -24,6 +24,7 @@
},
checkPlayCount: function() {
var _this = this;
if (document.cookie.indexOf("sessionId")) {
$.getJSON("/ajax/session_play_count", function(data) {
console.log("utils: got playcount");

View File

@@ -1,16 +1,17 @@
// Generated by CoffeeScript 1.3.3
// Generated by CoffeeScript 1.6.2
(function() {
var __hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
define(['marionette', 'text!/tpl/ActivityListItemView'], function(Marionette, Template) {
var ActivityItemView;
return ActivityItemView = (function(_super) {
var ActivityItemView, _ref;
return ActivityItemView = (function(_super) {
__extends(ActivityItemView, _super);
function ActivityItemView() {
return ActivityItemView.__super__.constructor.apply(this, arguments);
_ref = ActivityItemView.__super__.constructor.apply(this, arguments);
return _ref;
}
ActivityItemView.prototype.template = _.template(Template);

View File

@@ -1,16 +1,17 @@
// Generated by CoffeeScript 1.3.3
// Generated by CoffeeScript 1.6.2
(function() {
var __hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
define(['marionette', 'models/activity/activityCollection', 'views/activity/activityItemView', 'text!/tpl/ActivityListView'], function(Marionette, ActivityCollection, ActivityItemView, Template) {
var ActivityListView;
ActivityListView = (function(_super) {
var ActivityListView, _ref;
ActivityListView = (function(_super) {
__extends(ActivityListView, _super);
function ActivityListView() {
return ActivityListView.__super__.constructor.apply(this, arguments);
_ref = ActivityListView.__super__.constructor.apply(this, arguments);
return _ref;
}
ActivityListView.prototype.template = _.template(Template);
@@ -25,6 +26,7 @@
ActivityListView.prototype.initialize = function() {
var _this = this;
console.log("ActivityListView: initialize");
this.collection = new ActivityCollection;
this.collection.fetch({

View File

@@ -1,16 +1,17 @@
// Generated by CoffeeScript 1.3.3
// Generated by CoffeeScript 1.6.2
(function() {
var __hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
define(['marionette', 'text!/tpl/CommentItemView'], function(Marionette, Template) {
var CommentItemView;
CommentItemView = (function(_super) {
var CommentItemView, _ref;
CommentItemView = (function(_super) {
__extends(CommentItemView, _super);
function CommentItemView() {
return CommentItemView.__super__.constructor.apply(this, arguments);
_ref = CommentItemView.__super__.constructor.apply(this, arguments);
return _ref;
}
CommentItemView.prototype.template = _.template(Template);

View File

@@ -6,7 +6,8 @@
Copyright (c) 2012, Fergal Moran. All rights reserved.
Code provided under the BSD License:
###
define ["underscore", "backbone", "vent", "utils", "text!/tpl/HeaderView"], (_, Backbone, vent, utils, Template) ->
define ["underscore", "backbone", "vent", "utils", "text!/tpl/HeaderView"],
(_, Backbone, vent, utils, Template) ->
class HeaderView extends Backbone.View
template: _.template(Template)
events:
@@ -42,15 +43,7 @@ define ["underscore", "backbone", "vent", "utils", "text!/tpl/HeaderView"], (_,
this
playLive: ->
ref = this
dssSoundHandler.playLive()
_eventAggregator.trigger "track_playing"
button = $(@el).find("#header-play-pause-button")
button.data "mode", "pause"
$.getJSON "ajax/live_now_playing/", (data) ->
alert data.title
$(ref.el).find("#live-now-playing").text data.title
vent.trigger('live:play')
togglePlayState: ->
button = $(@el).find("#header-play-pause-button")

View File

@@ -1,5 +1,4 @@
// Generated by CoffeeScript 1.3.3
// Generated by CoffeeScript 1.6.2
/*
@license
@@ -15,13 +14,14 @@ Code provided under the BSD License:
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
define(["underscore", "backbone", "vent", "utils", "text!/tpl/HeaderView"], function(_, Backbone, vent, utils, Template) {
var HeaderView;
HeaderView = (function(_super) {
var HeaderView, _ref;
HeaderView = (function(_super) {
__extends(HeaderView, _super);
function HeaderView() {
return HeaderView.__super__.constructor.apply(this, arguments);
_ref = HeaderView.__super__.constructor.apply(this, arguments);
return _ref;
}
HeaderView.prototype.template = _.template(Template);
@@ -67,20 +67,12 @@ Code provided under the BSD License:
};
HeaderView.prototype.playLive = function() {
var button, ref;
ref = this;
dssSoundHandler.playLive();
_eventAggregator.trigger("track_playing");
button = $(this.el).find("#header-play-pause-button");
button.data("mode", "pause");
return $.getJSON("ajax/live_now_playing/", function(data) {
alert(data.title);
return $(ref.el).find("#live-now-playing").text(data.title);
});
return vent.trigger('live:play');
};
HeaderView.prototype.togglePlayState = function() {
var button, mode;
button = $(this.el).find("#header-play-pause-button");
mode = button.data("mode");
if (mode === "play") {

View File

@@ -1,26 +1,22 @@
// Generated by CoffeeScript 1.3.3
// Generated by CoffeeScript 1.6.2
(function() {
var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
define(['moment', 'app', 'vent', 'marionette', 'models/comment/commentCollection', 'views/comment/commentListView', 'text!/tpl/MixListItemView'], function(moment, App, vent, Marionette, CommentsCollection, CommentsListView, Template) {
var MixItemView;
MixItemView = (function(_super) {
var MixItemView, _ref;
MixItemView = (function(_super) {
__extends(MixItemView, _super);
function MixItemView() {
this.doStart = __bind(this.doStart, this);
this.renderComments = __bind(this.renderComments, this);
this.renderGenres = __bind(this.renderGenres, this);
this.onRender = __bind(this.onRender, this);
this.initialize = __bind(this.initialize, this);
return MixItemView.__super__.constructor.apply(this, arguments);
this.initialize = __bind(this.initialize, this); _ref = MixItemView.__super__.constructor.apply(this, arguments);
return _ref;
}
MixItemView.prototype.template = _.template(Template);
@@ -54,6 +50,7 @@
MixItemView.prototype.onRender = function() {
var id, totalDuration, totalDurationText;
id = this.model.get('id');
if (this.model.get('duration')) {
totalDuration = moment.duration(this.model.get('duration'), "seconds");
@@ -73,6 +70,7 @@
MixItemView.prototype.renderGenres = function() {
var el;
el = this.el;
$.each(this.model.get("genre-list"), function(data) {
$("#genre-list", el).append('<a href="/mixes/' + this.slug + '" class="dss-tag-button">' + this.text + '</a>');
@@ -83,6 +81,7 @@
MixItemView.prototype.renderComments = function() {
var comments;
comments = new CommentsCollection();
comments.url = this.model.get("resource_uri") + "comments/";
comments.mix_id = this.model.id;
@@ -90,6 +89,7 @@
comments.fetch({
success: function(data) {
var content;
console.log(data);
content = new CommentsListView({
collection: comments
@@ -133,6 +133,7 @@
MixItemView.prototype.mixFavourite = function() {
var app;
console.log("MixItemView: favouriteMix");
app = require('app');
app.vent.trigger("mix:favourite", this.model);
@@ -141,6 +142,7 @@
MixItemView.prototype.mixLike = function() {
var app;
console.log("MixItemView: likeMix");
app = require('app');
app.vent.trigger("mix:like", this.model);
@@ -149,6 +151,7 @@
MixItemView.prototype.mixShare = function(e) {
var app, mode;
console.log("MixItemView: shareMix");
mode = $(e.currentTarget).data("mode");
console.log("MixItemView: " + mode);

View File

@@ -1,19 +1,20 @@
// Generated by CoffeeScript 1.3.3
// Generated by CoffeeScript 1.6.2
(function() {
var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
define(['marionette', 'vent', 'models/mix/mixCollection', 'views/mix/mixItemView', 'text!/tpl/MixListView'], function(Marionette, vent, MixCollection, MixItemView, Template) {
var MixListView;
var MixListView, _ref;
MixListView = (function(_super) {
var currentMix;
__extends(MixListView, _super);
function MixListView() {
this.initialize = __bind(this.initialize, this);
return MixListView.__super__.constructor.apply(this, arguments);
this.initialize = __bind(this.initialize, this); _ref = MixListView.__super__.constructor.apply(this, arguments);
return _ref;
}
MixListView.prototype.template = _.template(Template);
@@ -28,6 +29,7 @@
MixListView.prototype.initialize = function() {
var _this = this;
console.log("MixListView: initialize");
this.collection = new MixCollection();
this.collection.fetch({
@@ -43,6 +45,7 @@
MixListView.prototype.mixPlay = function(model) {
var v;
console.log("MixListView: mixPlay");
if (currentMix !== -1) {
v = this.children.findByModelCid(currentMix);

View File

@@ -13,6 +13,7 @@ define ['underscore', 'backbone', 'marionette', 'vent', 'views/activity/activity
this.listenTo(vent, 'mix:init', @mixInit)
this.listenTo(vent, 'mix:play', @mixPlay)
this.listenTo(vent, 'mix:pause', @mixPause)
this.listenTo(vent, 'live:started', @liveStarted)
return
onRender: ->
@@ -38,5 +39,20 @@ define ['underscore', 'backbone', 'marionette', 'vent', 'views/activity/activity
$(@topRegion.el).show()
@topRegion.show(new NowPlayingView({model: model}))
liveStarted: ->
console.log "SidebarView: livePlay"
$.getJSON "ajax/live_now_playing/", (data) =>
$(@topRegion.el).show()
@topRegion.show(new NowPlayingView({
model: new Backbone.Model({
mix_image: "/static/img/radio.jpg",
item_url: "",
title: data.Description,
user_profile_url: "",
user_name: "Deep South Sounds Radio"
})
}))
true
SidebarView

View File

@@ -1,16 +1,17 @@
// Generated by CoffeeScript 1.3.3
// Generated by CoffeeScript 1.6.2
(function() {
var __hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
define(['underscore', 'backbone', 'marionette', 'vent', 'views/activity/activityListView', 'views/widgets/nowPlayingView', 'text!/tpl/SidebarView'], function(_, Backbone, Marionette, vent, ActivityListView, NowPlayingView, Template) {
var SidebarView;
SidebarView = (function(_super) {
var SidebarView, _ref;
SidebarView = (function(_super) {
__extends(SidebarView, _super);
function SidebarView() {
return SidebarView.__super__.constructor.apply(this, arguments);
_ref = SidebarView.__super__.constructor.apply(this, arguments);
return _ref;
}
SidebarView.prototype.template = _.template(Template);
@@ -25,6 +26,7 @@
this.listenTo(vent, 'mix:init', this.mixInit);
this.listenTo(vent, 'mix:play', this.mixPlay);
this.listenTo(vent, 'mix:pause', this.mixPause);
this.listenTo(vent, 'live:started', this.liveStarted);
};
SidebarView.prototype.onRender = function() {
@@ -36,7 +38,6 @@
this.streamRegion.show(new ActivityListView());
$(this.topRegion.el).hide();
"@topRegion.show(\n new NowPlayingView(\n model: new Backbone.Model({\n item_url: \"fdskjfhdsk\", title: \"Argle bargle\", user_profile_url: \"/\", user_name: \"Foo Ferra\"\n })\n ))";
};
SidebarView.prototype.mixInit = function(model) {
@@ -47,6 +48,25 @@
}));
};
SidebarView.prototype.liveStarted = function() {
var _this = this;
console.log("SidebarView: livePlay");
$.getJSON("ajax/live_now_playing/", function(data) {
$(_this.topRegion.el).show();
return _this.topRegion.show(new NowPlayingView({
model: new Backbone.Model({
mix_image: "/static/img/radio.jpg",
item_url: "",
title: data.Description,
user_profile_url: "",
user_name: "Deep South Sounds Radio"
})
}));
});
return true;
};
return SidebarView;
})(Marionette.Layout);

View File

@@ -1,18 +1,18 @@
// Generated by CoffeeScript 1.3.3
// Generated by CoffeeScript 1.6.2
(function() {
var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
define(['jquery', 'marionette', 'models/user/userCollection', 'views/user/userItemView', 'text!/tpl/UserListView', 'libs/bootstrap/bootpag'], function($, Marionette, UserCollection, UserItemView, Template) {
var UserListView;
UserListView = (function(_super) {
var UserListView, _ref;
UserListView = (function(_super) {
__extends(UserListView, _super);
function UserListView() {
this.initialize = __bind(this.initialize, this);
return UserListView.__super__.constructor.apply(this, arguments);
this.initialize = __bind(this.initialize, this); _ref = UserListView.__super__.constructor.apply(this, arguments);
return _ref;
}
UserListView.prototype.template = _.template(Template);
@@ -23,6 +23,7 @@
UserListView.prototype.initialize = function() {
var _this = this;
console.log("UserListView: initialize");
this.collection = new UserCollection();
this.collection.fetch({

View File

@@ -1,16 +1,17 @@
// Generated by CoffeeScript 1.3.3
// Generated by CoffeeScript 1.6.2
(function() {
var __hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
define(['marionette', 'vent', 'text!/tpl/NowPlayingView'], function(Marionette, vent, Template) {
var NowPlayingView;
NowPlayingView = (function(_super) {
var NowPlayingView, _ref;
NowPlayingView = (function(_super) {
__extends(NowPlayingView, _super);
function NowPlayingView() {
return NowPlayingView.__super__.constructor.apply(this, arguments);
_ref = NowPlayingView.__super__.constructor.apply(this, arguments);
return _ref;
}
NowPlayingView.prototype.template = _.template(Template);

View File

@@ -0,0 +1,313 @@
(function($) {
'use strict';
$('audio[controls]').before(function(){
var song = this;
song.controls=false;
var player_box = document.createElement('div');
$(player_box).addClass($(song).attr('class') + ' well container-fluid playa');
var data_sec = document.createElement('section');
$(data_sec).addClass('collapse');
var toggle_holder = document.createElement('div');
$(toggle_holder).addClass('btn-group row-fluid');
var data_toggle = document.createElement('a');
$(data_toggle).html('<i class="icon-reorder"></i>');
$(data_toggle).addClass('btn btn-block');
$(data_toggle).attr('style', 'opacity:0.3');
$(data_toggle).click(function (){$(data_sec).collapse('toggle');});
$(data_toggle).attr('title', 'Details');
$(data_toggle).tooltip({'container': 'body', 'placement': 'top', 'html': true});
$(toggle_holder).append(data_toggle);
var data_table = document.createElement('table');
$(data_table).addClass('table table-condensed');
var player = document.createElement('section');
$(player).addClass('btn-group row-fluid');
var load_error = function(){
console.log('error');
$(player_box).find('.btn').addClass('disabled');
$(player_box).find('input[type="range"]').hide();
$(player_box).find('.icon-spin').text('Error');
$(player_box).find('.icon-spin').parent().attr('title', 'There was an error loading the audio.');
$(player_box).find('.icon-spin').parent().tooltip('fixTitle');
$(player_box).find('.icon-spin').removeClass('icon-spinner icon-spin');
};
var addPlay = function() {
var play = document.createElement('button');
$(play).addClass('btn disabled span1');
play.setPlayState = function(toggle){
$(play).removeClass('disabled');
if (toggle === 'play') {
$(play).html('<i class="icon-play"></i>');
$(play).click(function () {
song.play();
});
}
if (toggle === 'pause') {
$(play).html('<i class="icon-pause"></i>');
$(play).click(function () {
song.pause();
});
}
};
$(song).on('play', function(){play.setPlayState('pause');});
$(song).on('canplay', function(){play.setPlayState('play');});
$(song).on('pause', function(){play.setPlayState('play');});
var timeout = 0;
var loadCheck = setInterval(function() {
if(isNaN(song.duration) === false){
play.setPlayState('play');
clearInterval(loadCheck);
return true;
}
if(song.networkState === 3 || timeout === 75){
load_error();
clearInterval(loadCheck);
return false;
}
timeout++;
}, 50);
$(player).append(play);
};
var addSeek = function() {
var seek = document.createElement('input');
$(seek).attr({
'type': 'range',
'min': 0,
'value': 0,
'class': 'seek'
});
seek.progress = function () {
var bg = 'rgba(223, 240, 216, 1) 0%';
bg += ', rgba(223, 240, 216, 1) ' + ((song.currentTime/song.duration) * 100) + '%';
bg += ', rgba(223, 240, 216, 0) ' + ((song.currentTime/song.duration) * 100) + '%';
for (var i=0; i<song.buffered.length; i++){
if (song.buffered.end(i) > song.currentTime && isNaN(song.buffered.end(i)) === false && isNaN(song.buffered.start(i)) === false){
var bufferedstart;
var bufferedend;
if (song.buffered.end(i) < song.duration) {
bufferedend = ((song.buffered.end(i)/song.duration) * 100);
}
else {
bufferedend = 100;
}
if (song.buffered.start(i) > song.currentTime){
bufferedstart = ((song.buffered.start(i)/song.duration) * 100);
}
else {
bufferedstart = ((song.currentTime/song.duration) * 100);
}
bg += ', rgba(217, 237, 247, 0) ' + bufferedstart + '%';
bg += ', rgba(217, 237, 247, 1) ' + bufferedstart + '%';
bg += ', rgba(217, 237, 247, 1) ' + bufferedend + '%';
bg += ', rgba(217, 237, 247, 0) ' + bufferedend + '%';
}
}
$(seek).css('background', '-webkit-linear-gradient(left, ' + bg + ')');
//These may be re-enabled when/if other browsers support the background like webkit
//$(seek).css('background','-o-linear-gradient(left, ' + bg + ')');
//$(seek).css('background','-moz-linear-gradient(left, ' + bg + ')');
//$(seek).css('background','-ms-linear-gradient(left, ' + bg + ')');
//$(seek).css('background','linear-gradient(to right, ' + bg + ')');
$(seek).css('background-color', '#ddd');
};
seek.set = function () {
$(seek).val(song.currentTime);
seek.progress();
};
seek.slide = function () {
song.currentTime = $(seek).val();
seek.progress();
};
seek.init = function () {
$(seek).attr({
'max': song.duration,
'step': song.duration / 100
});
seek.set();
};
seek.reset = function () {
$(seek).val(0);
song.currentTime = $(seek).val();
if(!song.loop){song.pause();}
else {song.play();}
};
var seek_wrapper = document.createElement('div');
$(seek_wrapper).addClass('btn disabled span4');
$(seek_wrapper).append(seek);
$(seek).on('change', seek.slide);
$(song).on('timeupdate', seek.init);
$(song).on('loadedmetadata', seek.init);
$(song).on('loadeddata', seek.init);
$(song).on('progress', seek.init);
$(song).on('canplay', seek.init);
$(song).on('canplaythrough', seek.init);
$(song).on('ended', seek.reset);
if(song.readyState > 0){
seek.init();
}
$(player).append(seek_wrapper);
};
var addTime = function() {
var time = document.createElement('a');
$(time).addClass('btn span3');
$(time).tooltip({'container': 'body', 'placement': 'right', 'html': true});
time.twodigit = function (myNum) {
return ("0" + myNum).slice(-2);
};
time.timesplit = function (a) {
if (isNaN(a)){return '<i class="icon-spinner icon-spin"></i>';}
var hours = Math.floor(a / 3600);
var minutes = Math.floor(a / 60) - (hours * 60);
var seconds = Math.floor(a) - (hours * 3600) - (minutes * 60);
var timeStr = time.twodigit(minutes) + ':' + time.twodigit(seconds);
if (hours > 0) {
timeStr = hours + ':' + timeStr;
}
return timeStr;
};
time.showtime = function () {
$(time).html(time.timesplit(song.duration));
$(time).attr({'title': 'Click to Reset<hr style="padding:0; margin:0;" />Position: ' + (time.timesplit(song.currentTime))});
if (!song.paused){
$(time).html(time.timesplit(song.currentTime));
$(time).attr({'title': 'Click to Reset<hr style="padding:0; margin:0;" />Length: ' + (time.timesplit(song.duration))});
}
$(time).tooltip('fixTitle');
};
$(time).click(function () {
song.pause();
song.currentTime = 0;
time.showtime();
$(time).tooltip('fixTitle');
$(time).tooltip('show');
});
$(time).tooltip('show');
$(song).on('loadedmetadata', time.showtime);
$(song).on('loadeddata', time.showtime);
$(song).on('progress', time.showtime);
$(song).on('canplay', time.showtime);
$(song).on('canplaythrough', time.showtime);
$(song).on('timeupdate', time.showtime);
if(song.readyState > 0){
time.showtime();
}
else {
$(time).html('<i class="icon-spinner icon-spin"></i>');
}
$(player).append(time);
};
var addMute = function() {
var mute = document.createElement('button');
$(mute).addClass('btn span1');
mute.checkVolume = function () {
if (song.volume > 0.5 && !song.muted) {
$(mute).html('<i class="icon-volume-up"></i>');
} else if (song.volume < 0.5 && song.volume > 0 && !song.muted) {
$(mute).html('<i class="icon-volume-down"></i>');
} else {
$(mute).html('<i class="icon-volume-off"></i>');
}
};
$(mute).click(function () {
if (song.muted) {
song.muted = false;
song.volume = song.oldvolume;
} else {
song.muted = true;
song.oldvolume = song.volume;
song.volume = 0;
}
mute.checkVolume();
});
mute.checkVolume();
$(song).on('volumechange', mute.checkVolume);
$(player).append(mute);
};
var addVolume = function() {
var volume = document.createElement('input');
$(volume).attr({
'type': 'range',
'min': 0,
'max': 1,
'step': 1 / 100,
'value': 1
});
volume.slide = function () {
song.muted = false;
song.volume = $(volume).val();
};
volume.set = function () {
$(volume).val(song.volume);
};
var vol_wrapper = document.createElement('div');
$(vol_wrapper).addClass('btn disabled span3');
$(vol_wrapper).append(volume);
$(volume).on("change", volume.slide);
$(song).on('volumechange', volume.set);
$(player).append(vol_wrapper);
};
var addAlbumArt = function() {
var albumArt = document.createElement('img');
$(albumArt).addClass('thumbnail');
$(albumArt).attr('src', $(song).data('infoAlbumArt'));
$(data_sec).append(albumArt);
};
var addInfo = function(title, dataId) {
var row = document.createElement('tr');
var head = document.createElement('th');
var data = document.createElement('td');
$(head).html(title);
$(data).html($(song).data(dataId));
$(row).append(head);
$(row).append(data);
$(data_table).append(row);
};
var addData = function() {
if (typeof($(song).data('infoAlbumArt')) !== 'undefined'){ addAlbumArt();}
if (typeof($(song).data('infoArtist')) !== 'undefined'){ addInfo('Artist', 'infoArtist');}
if (typeof($(song).data('infoTitle')) !== 'undefined'){ addInfo('Title', 'infoTitle');}
if (typeof($(song).data('infoAlbumTitle')) !== 'undefined'){ addInfo('Album', 'infoAlbumTitle');}
if (typeof($(song).data('infoLabel')) !== 'undefined'){ addInfo('Label', 'infoLabel');}
if (typeof($(song).data('infoYear')) !== 'undefined'){ addInfo('Year', 'infoYear');}
if ($(data_table).html() !== ""){
$(data_sec).append(data_table);
$(player_box).append(toggle_holder);
$(player_box).append(data_sec);
}
};
var addPlayer = function() {
if ($(song).data('play') !== 'off'){ addPlay();}
if ($(song).data('seek') !== 'off'){ addSeek();}
if ($(song).data('time') !== 'off'){ addTime();}
if ($(song).data('mute') !== 'off'){ addMute();}
if ($(song).data('volume') !== 'off'){ addVolume();}
$(player_box).append(player);
};
var addAttribution = function() {
var attribution = document.createElement('small');
$(attribution).addClass('pull-right muted');
if (typeof($(song).data('infoAttLink')) !== 'undefined'){
var attribution_link = document.createElement('a');
$(attribution_link).addClass('muted');
$(attribution_link).attr('href', $(song).data('infoAttLink'));
$(attribution_link).html($(song).data('infoAtt'));
$(attribution).append(attribution_link);
}
else {
$(attribution).html($(song).data('infoAtt'));
}
$(player_box).append(attribution);
};
var fillPlayerBox = function() {
addData();
addPlayer();
if (typeof($(song).data('infoAtt')) !== 'undefined'){ addAttribution();}
};
fillPlayerBox();
$(song).on('error', function(){
load_error();
});
return player_box;
});
})(jQuery)

View File

@@ -0,0 +1,284 @@
/*
html5slider - a JS implementation of <input type=range> for Firefox 16 and up
https://github.com/fryn/html5slider
Copyright (c) 2010-2012 Frank Yan, <http://frankyan.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
(function () {
// test for native support
var test = document.createElement('input');
try {
test.type = 'range';
if (test.type == 'range')
return;
} catch (e) {
return;
}
// test for required property support
test.style.background = 'linear-gradient(red, red)';
if (!test.style.backgroundImage || !('MozAppearance' in test.style) || !document.mozSetImageElement || !this.MutationObserver)
return;
var scale;
var isMac = navigator.platform == 'MacIntel';
var thumb = {
radius: isMac ? 9 : 6,
width: isMac ? 22 : 12,
height: isMac ? 16 : 20
};
var track = 'linear-gradient(transparent ' + (isMac ?
'6px, #999 6px, #999 7px, #ccc 8px, #bbb 9px, #bbb 10px, transparent 10px' :
'9px, #999 9px, #bbb 10px, #fff 11px, transparent 11px') +
', transparent)';
var styles = {
'min-width': thumb.width + 'px',
'min-height': thumb.height + 'px',
'max-height': thumb.height + 'px',
padding: '0 0 ' + (isMac ? '2px' : '1px'),
border: 0,
'border-radius': 0,
cursor: 'default',
'text-indent': '-999999px' // -moz-user-select: none; breaks mouse capture
};
var options = {
attributes: true,
attributeFilter: ['min', 'max', 'step', 'value']
};
var forEach = Array.prototype.forEach;
var onChange = document.createEvent('HTMLEvents');
onChange.initEvent('change', true, false);
if (document.readyState == 'loading')
document.addEventListener('DOMContentLoaded', initialize, true);
else
initialize();
function initialize() {
// create initial sliders
forEach.call(document.querySelectorAll('input[type=range]'), transform);
// create sliders on-the-fly
new MutationObserver(function (mutations) {
mutations.forEach(function (mutation) {
if (mutation.addedNodes)
forEach.call(mutation.addedNodes, function (node) {
check(node);
if (node.childElementCount)
forEach.call(node.querySelectorAll('input'), check);
});
});
}).observe(document, { childList: true, subtree: true });
}
function check(input) {
if (input.localName == 'input' && input.type != 'range' &&
input.getAttribute('type') == 'range')
transform(input);
}
function transform(slider) {
var isValueSet, areAttrsSet, isChanged, isClick, prevValue, rawValue, prevX;
var min, max, step, range, value = slider.value;
// lazily create shared slider affordance
if (!scale) {
scale = document.body.appendChild(document.createElement('hr'));
style(scale, {
'-moz-appearance': isMac ? 'scale-horizontal' : 'scalethumb-horizontal',
display: 'block',
visibility: 'visible',
opacity: 1,
position: 'fixed',
top: '-999999px'
});
document.mozSetImageElement('__sliderthumb__', scale);
}
// reimplement value and type properties
var getValue = function () {
return '' + value;
};
var setValue = function setValue(val) {
value = '' + val;
isValueSet = true;
draw();
delete slider.value;
slider.value = value;
slider.__defineGetter__('value', getValue);
slider.__defineSetter__('value', setValue);
};
slider.__defineGetter__('value', getValue);
slider.__defineSetter__('value', setValue);
slider.__defineGetter__('type', function () {
return 'range';
});
// sync properties with attributes
['min', 'max', 'step'].forEach(function (prop) {
if (slider.hasAttribute(prop))
areAttrsSet = true;
slider.__defineGetter__(prop, function () {
return this.hasAttribute(prop) ? this.getAttribute(prop) : '';
});
slider.__defineSetter__(prop, function (val) {
val === null ? this.removeAttribute(prop) : this.setAttribute(prop, val);
});
});
// initialize slider
slider.readOnly = true;
style(slider, styles);
update();
new MutationObserver(function (mutations) {
mutations.forEach(function (mutation) {
if (mutation.attributeName != 'value') {
update();
areAttrsSet = true;
}
// note that value attribute only sets initial value
else if (!isValueSet) {
value = slider.getAttribute('value');
draw();
}
});
}).observe(slider, options);
slider.addEventListener('mousedown', onDragStart, true);
slider.addEventListener('keydown', onKeyDown, true);
slider.addEventListener('focus', onFocus, true);
slider.addEventListener('blur', onBlur, true);
function onDragStart(e) {
isClick = true;
setTimeout(function () {
isClick = false;
}, 0);
if (e.button || !range)
return;
var width = parseFloat(getComputedStyle(this, 0).width);
var multiplier = (width - thumb.width) / range;
if (!multiplier)
return;
// distance between click and center of thumb
var dev = e.clientX - this.getBoundingClientRect().left - thumb.width / 2 -
(value - min) * multiplier;
// if click was not on thumb, move thumb to click location
if (Math.abs(dev) > thumb.radius) {
isChanged = true;
this.value -= -dev / multiplier;
}
rawValue = value;
prevX = e.clientX;
this.addEventListener('mousemove', onDrag, true);
this.addEventListener('mouseup', onDragEnd, true);
}
function onDrag(e) {
var width = parseFloat(getComputedStyle(this, 0).width);
var multiplier = (width - thumb.width) / range;
if (!multiplier)
return;
rawValue += (e.clientX - prevX) / multiplier;
prevX = e.clientX;
isChanged = true;
this.value = rawValue;
}
function onDragEnd() {
this.removeEventListener('mousemove', onDrag, true);
this.removeEventListener('mouseup', onDragEnd, true);
}
function onKeyDown(e) {
if (e.keyCode > 36 && e.keyCode < 41) { // 37-40: left, up, right, down
onFocus.call(this);
isChanged = true;
this.value = value + (e.keyCode == 38 || e.keyCode == 39 ? step : -step);
}
}
function onFocus() {
if (!isClick)
this.style.boxShadow = !isMac ? '0 0 0 2px #fb0' :
'inset 0 0 20px rgba(0,127,255,.1), 0 0 1px rgba(0,127,255,.4)';
}
function onBlur() {
this.style.boxShadow = '';
}
// determines whether value is valid number in attribute form
function isAttrNum(value) {
return !isNaN(value) && +value == parseFloat(value);
}
// validates min, max, and step attributes and redraws
function update() {
min = isAttrNum(slider.min) ? +slider.min : 0;
max = isAttrNum(slider.max) ? +slider.max : 100;
if (max < min)
max = min > 100 ? min : 100;
step = isAttrNum(slider.step) && slider.step > 0 ? +slider.step : 1;
range = max - min;
draw(true);
}
// recalculates value property
function calc() {
if (!isValueSet && !areAttrsSet)
value = slider.getAttribute('value');
if (!isAttrNum(value))
value = (min + max) / 2;
;
// snap to step intervals (WebKit sometimes does not - bug?)
value = Math.round((value - min) / step) * step + min;
if (value < min)
value = min;
else if (value > max)
value = min + ~~(range / step) * step;
}
// renders slider using CSS background ;)
function draw(attrsModified) {
calc();
if (isChanged && value != prevValue)
slider.dispatchEvent(onChange);
isChanged = false;
if (!attrsModified && value == prevValue)
return;
prevValue = value;
var position = range ? (value - min) / range * 100 : 0;
var bg = '-moz-element(#__sliderthumb__) ' + position + '% no-repeat, ';
style(slider, { background: bg + track });
}
}
function style(element, styles) {
for (var prop in styles)
element.style.setProperty(prop, styles[prop], 'important');
}
})();

View File

@@ -9,6 +9,7 @@
{% compress css %}
<link rel="stylesheet" href="{{ STATIC_URL }}css/bootstrap.css">
<link rel="stylesheet" href="{{ STATIC_URL }}css/bootstrap-responsive.min.css">
<link href="http://netdna.bootstrapcdn.com/font-awesome/3.0.2/css/font-awesome.css" type="text/css" rel="stylesheet">
<link rel="stylesheet" href="{{ STATIC_URL }}css/bootstrap-datepicker.css">
<link rel="stylesheet" href="{{ STATIC_URL }}css/bootstrap-timepicker.css">
<link rel="stylesheet" href="{{ STATIC_URL }}css/jasny/jasny-bootstrap.css">
@@ -57,6 +58,7 @@
<script src="{{ STATIC_URL }}js/libs/jquery.tablesorter.js"></script>
<script src="{{ STATIC_URL }}js/libs/uploadify/jquery.uploadifive.js"></script>
<script src="{{ STATIC_URL }}js/libs/bootstrap/bootstrap.js"></script>
<script src="{{ STATIC_URL }}js/libs/bootstrap/html5slider.js"></script>
<script src="{{ STATIC_URL }}js/libs/jasny/bootstrap-fileupload.js"></script>
<script src="{{ STATIC_URL }}js/libs/modernizr.js"></script>
<script src="{{ STATIC_URL }}js/libs/point.js"></script>

View File

@@ -34,6 +34,9 @@
</li>
{% endif %}
</ul>
<a href="#" id="header-live-button" class="btn btn-success">
<i class="icon-headphones icon-white icon-spin" id="header-live-icon"></i>Listen Live
</a>
{% if user.is_authenticated %}
<a class="pull-right btn btn-primary" href="/mix/upload" id='upload'>
<i class="icon-hand-up icon-white"></i>Upload</a>

View File

@@ -2,7 +2,7 @@
<div class="now-playing-surround">
<div class="span2 now-playing-image-container">
<img src="http://www.deepsouthsounds.com/media//cache/11/16/1116b53513b111266fac440b9c924ce4.jpg"
<img src="<%= mix_image %>"
class="now-playing-image img-rounded">
</div>
<div class="span8 now-playing-bio">