* working on generic recording widget logic

This commit is contained in:
Seth Call 2014-02-28 19:28:17 +00:00
parent e7c1a791a7
commit b7a1e06889
19 changed files with 593 additions and 285 deletions

View File

@ -61,7 +61,7 @@ module JamRuby
def has_mix?
recording.mixes.length > 0 && recording.mixes.first.completed
recording.has_mix?
end
def can_download?(some_user)

View File

@ -43,6 +43,10 @@ module JamRuby
self.comments.size
end
def has_mix?
self.mixes.length > 0 && self.mixes.first.completed
end
# this can probably be done more efficiently, but David needs this asap for a video
def grouped_tracks
tracks = []

View File

@ -6,14 +6,46 @@
context.JK.FeedItemRecording = function($parentElement, options){
var $feedItem = $parentElement;
var $description = $('.description', $feedItem)
var $musicians = $('.musician-detail', $feedItem)
var $description = $('.description', $feedItem);
var $musicians = $('.musician-detail', $feedItem);
var $controls = $('.recording-controls', $feedItem);
var playing = false;
var toggledOpen = false;
if(!$feedItem.is('.feed-entry')) {
throw "$parentElement must be a .feed-entry"
}
function startPlay() {
var img = $('.play-icon', $feedItem);
img.attr('src', '/assets/content/icon_pausebutton.png');
$controls.trigger('play.listenRecording');
playing = true;
}
function stopPlay() {
var img = $('.play-icon', $feedItem);
img.attr('src', '/assets/content/icon_playbutton.png');
$controls.trigger('pause.listenRecording');
playing = false;
}
function togglePlay() {
if(playing) {
stopPlay();
}
else {
startPlay();
}
return false;
}
function stateChange(e, data) {
if(data.isEnd) stopPlay();
}
function toggleDetails() {
if(toggledOpen) {
$feedItem.css('height', $feedItem.height() + 'px')
@ -40,11 +72,14 @@
function events() {
$('.details', $feedItem).click(toggleDetails);
$('.details-arrow', $feedItem).click(toggleDetails);
$('.play-button', $feedItem).click(togglePlay);
$controls.bind('statechange.listenRecording', stateChange);
}
function initialize() {
$('.timeago', $feedItem).timeago();
$('.dotdotdot', $feedItem).dotdotdot();
$controls.listenRecording({sliderSelector:'.recording-slider', sliderBarSelector: '.recording-playback', currentTimeSelector:'.recording-current'});
context.JK.prettyPrintElements($('time.duration', $feedItem));
context.JK.setInstrumentAssetPath($('.instrument-icon', $feedItem));

View File

@ -35,6 +35,7 @@
$controls.trigger('pause.listenBroadcast');
playing = false;
}
function togglePlay() {
if(playing) {
$status.text('SESSION IN PROGRESS');
@ -83,7 +84,6 @@
$('.details', $feedItem).click(toggleDetails);
$('.details-arrow', $feedItem).click(toggleDetails);
$('.play-button', $feedItem).click(togglePlay);
$controls.bind('statechange.listenBroadcast', stateChange);
}
@ -91,29 +91,12 @@
$('.timeago', $feedItem).timeago();
$('.dotdotdot', $feedItem).dotdotdot();
$controls.listenBroadcast();
context.JK.prettyPrintElements($('time.duration', $feedItem));
context.JK.prettyPrintElements($('time.duration', $feedItem).show());
context.JK.setInstrumentAssetPath($('.instrument-icon', $feedItem));
$feedItem.data('original-max-height', $feedItem.css('height'));
events();
// this is a bit lame, because this is a singleton.
// the idea is, if there are any session widgets on the page, then we start ticking time
if(!context.JK.FeedItemSessionTimer) {
context.JK.FeedItemSessionTimer = setInterval(function() {
$.each($('.feed-entry.music-session-history-entry .inprogress .session-duration'), function(index, item) {
var $duration = $(item);
var createdAt = new Date(Number($duration.attr('data-created-at')) * 1000)
var millisElapsed = (new Date()).getTime() - createdAt.getTime();
console.log("createdAt, millis", createdAt, millisElapsed);
$duration.text(context.JK.prettyPrintSeconds( parseInt(millisElapsed / 1000)));
});
}, 333);
}
}
initialize();

View File

@ -0,0 +1,377 @@
(function(context, $) {
"use strict";
context.JK = context.JK || {};
// the purpose of this code is to simply the interaction for recording widgets
context.JK.ListenRecording = function($parentElement, options){
var WAIT_FOR_BUFFER_TIMEOUT = 5000;
var logger = context.JK.logger;
var rest = context.JK.Rest();
var $parent = $parentElement;
var $currentTime = null;
var $slider = null;
var $sliderBar = null;
var $audio = null;
var audioDomElement = null;
var self = this;
var waitForBufferingTimeout = null;
var destroyed = false;
var lastTime = 0;
var dragging = false;
var PlayStateNone = 'none';
var PlayStateInitializing = 'initializing'; // user clicked play--nothing has happened yet
var PlayStateBuffering = 'buffering'; // user clicked play--the stream is being read, buffer is being built
var PlayStatePlaying = 'playing'; // we are playing
var PlayStateStalled = 'stalled'; // we were playing, but the stream is stalled
var PlayStateEnded = 'ended'; // we were playing, but the stream ended
var PlayStateFailedStart = 'failed_start'; // we could not start the stream. no more events are coming
var PlayStateFailedPlaying = 'failed_playing'; // failed while playing.
var PlayStateNetworkError = 'network_error'; // network error
var playState = PlayStateNone; // tracks if the stream is actually playing
var canPlay = false;
function play(e) {
if(e) {
e.preventDefault();
e.stopPropagation();
}
if(destroyed) return;
if(!audioDomElement) throw "no audio element supplied; the user should not be able to attempt a play"
if(canPlay) {
audioDomElement.currentTime = lastTime
}
audioDomElement.play();
transition(PlayStateInitializing);
// keep this after transition, because any transition clears this timer
waitForBufferingTimeout = setTimeout(noBuffer, WAIT_FOR_BUFFER_TIMEOUT);
}
function pause(e) {
if(e) {
e.preventDefault();
e.stopPropagation();
}
if(destroyed) return;
if(!audioDomElement) throw "no audio element supplied; the user should not be able to attempt a pause"
transition(PlayStateNone);
audioDomElement.pause();
//recreateAudioElement();
}
function destroy() {
if(!destroyed) {
$audio.remove();
$audio = null;
audioDomElement = null;
destroyed = true;
}
}
function noBuffer() {
logger.debug("never received indication of buffering or playing");
transition(PlayStateFailedStart);
}
// this is the only way to make audio stop buffering after the user hits pause
function recreateAudioElement() {
// jeez: http://stackoverflow.com/questions/4071872/html5-video-force-abort-of-buffering/13302599#13302599
var originalSource = $audio.html()
audioDomElement.pause();
audioDomElement.src = '';
audioDomElement.load();
var $parent = $audio.parent();
$audio.remove();
$parent.append('<audio preload="none"></audio>');
$audio = $('audio', $parent);
$audio.append(originalSource);
audioDomElement = $audio.get(0);
audioBind();
}
function clearBufferTimeout() {
if(waitForBufferingTimeout) {
clearTimeout (waitForBufferingTimeout);
waitForBufferingTimeout = null;
}
}
function transition(newState) {
logger.debug("transitioning from " + playState + " to " + newState);
playState = newState;
clearBufferTimeout();
if( playState == PlayStateNone ||
playState == PlayStateEnded ||
playState == PlayStateFailedStart ||
playState == PlayStateFailedPlaying ||
playState == PlayStateNetworkError) {
context.JK.ListenBroadcastCurrentlyPlaying = null;
}
triggerStateChange();
}
function isNoisyEvent(eventName) {
if(playState == PlayStateNone) {
console.log("ignoring: " + eventName)
return true;
}
return false;
}
function onPlay() {
// this just confirms that the user tried to play
}
function onPlaying() {
if(isNoisyEvent('playing')) return;
logger.debug("playing", arguments);
transition(PlayStatePlaying);
}
function onPause() {
if(isNoisyEvent('pause')) return;
logger.debug("pause", arguments);
transition(PlayStateStalled);
}
function onError() {
if(isNoisyEvent('error')) return;
logger.debug("error", arguments);
if(playState == PlayStatePlaying || playState == PlayStateStalled) {
transition(PlayStateFailedPlaying);
}
else {
transition(PlayStateFailedStart);
}
}
function onEnded() {
if(isNoisyEvent('ended')) return;
logger.debug("ended", arguments);
transition(PlayStateEnded);
}
function onEmptied() {
if(isNoisyEvent('emptied')) return;
logger.debug("emptied", arguments);
}
function onAbort() {
if(isNoisyEvent('abort')) return;
logger.debug("abort", arguments);
}
function onStalled() {
if(isNoisyEvent('stalled')) return;
logger.debug("stalled", arguments);
// fires in Chrome on page load
if(playState == PlayStateBuffering || playState == PlayStatePlaying) {
transition(PlayStateStalled);
}
}
function onSuspend() {
if(isNoisyEvent('suspend')) return;
logger.debug("onsuspend", arguments);
// fires in FF on page load
transition(PlayStateStalled);
}
function onTimeUpdate() {
if(dragging) {
return;
}
var percentComplete = (audioDomElement.currentTime / audioDomElement.duration) * 100;
updateSliderPosition(percentComplete);
$currentTime.html(context.JK.prettyPrintSeconds(parseInt(audioDomElement.currentTime)));
// reset icon to play and slider to far left when done
if (percentComplete === 100) {
updateSliderPosition(0);
$currentTime.html("0:00");
lastTime = 0
}
else {
lastTime = audioDomElement.currentTime;
}
}
function updateSliderPosition(percent) {
console.log("updateSliderPosition", percent)
$slider.css({'left': percent + '%'});
}
function onProgress() {
if(isNoisyEvent('progress')) return;
if(playState == PlayStateInitializing) {
transition(PlayStateBuffering);
}
}
function startDrag(e, ui) {
dragging = true;
}
function stopDrag(e, ui) {
dragging = false;
var percent = ui.position.left / $sliderBar.width() * 100;
updateSliderPosition(percent);
audioDomElement.currentTime = percent * audioDomElement.duration;
}
function onDrag(e, ui) {
updateSliderPosition(ui.position.left / $sliderBar.width() * 100);
}
function triggerStateChange() {
var isEnd = false;
var displayText = null;
var refresh = false;
if(playState == 'none') {
//$status.text('SESSION IN PROGRESS');
}
else if(playState == 'initializing') {
displayText = 'PREPARING AUDIO';
}
else if(playState == 'buffering') {
}
else if(playState == 'playing') {
displayText = 'PLAYING';
}
else if(playState == 'stalled') {
displayText = 'RECONNECTING';
}
else if(playState == 'ended') {
displayText = 'DISCONNECTED';
isEnd = true;
}
else if(playState == 'failed_start') {
displayText = 'AUDIO DID NOT START';
isEnd = true;
}
else if(playState == 'failed_playing') {
displayText = 'STREAM DISCONNECTED';
isEnd = true;
}
else if(playState == 'network_error') {
displayText = 'NO NETWORK';
isEnd = true;
}
else {
logger.error("unknown state: " + playState)
}
$parent.triggerHandler('statechange.listenRecording',
{
state: playState,
displayText: displayText,
isEnd: isEnd
})
}
function audioBind() {
$audio.bind('play', onPlay);
$audio.bind('playing', onPlaying);
$audio.bind('error', onError);
$audio.bind('emptied', onEmptied);
$audio.bind('abort', onAbort);
$audio.bind('ended', onEnded);
$audio.bind('pause', onPause);
$audio.bind('suspend', onSuspend);
$audio.bind('stalled', onStalled);
$audio.bind('timeupdate', onTimeUpdate);
$audio.bind('progress', onProgress);
$audio.bind('canplay', function() { canPlay = true;})
}
function initialize() {
$slider = $(options.sliderSelector, $parent);
$sliderBar = $(options.sliderBarSelector, $parent);
$currentTime = $(options.currentTimeSelector, $parent);
$audio = $('audio', $parent);
if($audio.length == 0) {
logger.debug("listen_recording: no audio element. deactivating")
return;
}
if($audio.length > 1) {
throw "more than one <audio> element found";
}
audioDomElement = $audio.get(0);
audioBind();
$parent.bind('play.listenRecording', play);
$parent.bind('pause.listenRecording', pause);
$parent.bind('destroy.listenRecording', destroy);
$sliderBar.bind('click', function(e) {
var offset = e.pageX - $(this).offset().left;
var percent = offset / $sliderBar.width() * 100;
updateSliderPosition(percent);
audioDomElement.currentTime = percent * audioDomElement.duration;
return false;
});
$slider.draggable({
axis: 'x',
containment: $sliderBar,
start: startDrag,
stop: stopDrag,
drag: onDrag
});
}
initialize();
this.play = play;
this.pause = pause;
return this;
}
$.fn.listenRecording = function(options) {
new context.JK.ListenRecording(this, options);
}
})(window, jQuery);

View File

@ -17,7 +17,7 @@
*/
context.JK = context.JK || {};
// the purpose of this code is to simply the interaction between user and server
// the purpose of this code is to simplify the interaction between user and server
// it provides methods to call on user events (primarily play/pause), and will fire
// events (such as 'stream_gone'). This element does nothing with UI; only fires events for you to handle
@ -328,12 +328,12 @@
isEnd = true;
}
else if(playState == 'failed_playing') {
displayText = 'AUDIO FAILED';
displayText = 'STREAM DISCONNECTED';
isEnd = true;
refresh = true;
}
else if(playState == 'network_error') {
displayText = 'STREAM DISCONNECTED';
displayText = 'NO NETWORK';
isEnd = true;
}
else if(playState == 'server_error') {
@ -372,7 +372,7 @@
$audio.bind('pause', onPause);
$audio.bind('suspend', onSuspend);
$audio.bind('stalled', onStalled);
$audio.bind('timeupdate', onTimeUpdate);
//$audio.bind('timeupdate', onTimeUpdate);
$audio.bind('progress', onProgress);
}

View File

@ -210,7 +210,7 @@
promptLeave = false;
context.location = '/client#/home'
}
else {
else if(type != 30 && type != 31){ // these are handled elsewhere
context.setTimeout(function() {
var alert = alert_type[type];

View File

@ -5,7 +5,7 @@
context.JK = context.JK || {};
context.JK.TickDuration = function(customSelector) {
setInterval(function() {
$.each($(customSelector ? customSelector : '.tick-duration'), function(index, item) {
$.each($(customSelector ? customSelector : '.inprogress .tick-duration'), function(index, item) {
var $duration = $(item);
var createdAt = new Date(Number($duration.attr('data-created-at')) * 1000)
var millisElapsed = (new Date()).getTime() - createdAt.getTime();

View File

@ -3,8 +3,10 @@
context.JK.ShowMusicSession = function(app) {
var logger = context.JK.logger;
var rest = new JK.Rest();
var sessionId = null;
var sessionId = null;
var $controls = null;
var $status = null;
var playing = false;
function like() {
rest.addSessionLike(sessionId, JK.currentUserId)
@ -33,7 +35,61 @@
}
}
function stateChange(e, data) {
if(data.displayText)
{
if(data.displayText == 'SESSION IN PROGRESS') {
$status.text('LIVE SESSION IN PROGRESS');
}
else {
$status.text(data.displayText);
}
}
if(data.isEnd) stopPlay();
if(data.isSessionOver) {
$controls.removeClass('inprogress').addClass('ended')
}
}
function startPlay() {
var img = $('.play-icon');
img.attr('src', '/assets/content/icon_pausebutton.png');
$controls.trigger('play.listenBroadcast');
playing = true;
}
function stopPlay() {
var img = $('.play-icon');
img.attr('src', '/assets/content/icon_playbutton.png');
$controls.trigger('pause.listenBroadcast');
playing = false;
}
function togglePlay() {
if(playing) {
$status.text('SESSION IN PROGRESS');
stopPlay();
}
else {
startPlay();
}
return false;
}
function initialize(musicSessionId) {
$controls = $('.recording-controls');
$status = $('.session-status')
$('.timeago').timeago();
$controls.listenBroadcast();
$controls.bind('statechange.listenBroadcast', stateChange);
context.JK.prettyPrintElements($('time.duration').show());
context.JK.TickDuration(null);
$('.play-button').click(togglePlay);
sessionId = musicSessionId;
if (JK.currentUserId) {

View File

@ -1,6 +1,7 @@
//= require jquery
//= require jquery.monkeypatch
//= require jquery_ujs
//= require jquery.ui.draggable
//= require jquery.queryparams
//= require jquery.hoverIntent
//= require jquery.cookie
@ -11,6 +12,7 @@
//= require jquery.timeago
//= require jquery.dotdotdot
//= require jquery.listenbroadcast
//= require jquery.listenRecording
//= require AAA_Log
//= require AAC_underscore
//= require globals
@ -21,6 +23,7 @@
//= require web/signinDialog
//= require web/videoDialog
//= require invitationDialog
//= require tickDuration
//= require hoverMusician
//= require feed_item_recording
//= require feed_item_session

View File

@ -46,9 +46,10 @@
else {
new context.JK.FeedItemSession($feedEntry);
}
})
context.JK.TickDuration('.feed-entry.music-session-history-entry .inprogress .tick-duration');
}
context.JK.WelcomePage = initialize;

View File

@ -26,6 +26,72 @@
height: 36px;
}
.session-controls, .recording-controls {
.tick-duration {
display:none;
}
.play-button {
outline: 0;
}
.session-status {
font-size:18px;
display:inline;
}
.recording-current {
top:8px;
}
.session-duration {
top:8px;
}
&.ended {
.play-button {
display:none;
}
}
&.inprogress {
}
}
.feed-entry {
.session-controls, .recording-controls {
&.ended {
background-color: #471f18;
}
&.inprogress {
background-color: #4C742E;
.session-status {
font-size: 15px;
color: #cccc00;
margin:auto;
}
}
}
.recording-controls {
.recording-position {
width:70%;
margin-left:0;
}
.recording-time {
display:inline;
}
}
}
.feed-entry {
position:relative;
display:block;
@ -58,25 +124,6 @@
}
*/
.session-status {
float:left;
font-size:18px;
}
.inprogress {
.session-status {
font-size: 15px;
color: #cccc00;
margin-left:20px;
}
}
.recording-current {
top:8px;
}
.session-duration {
top:8px;
}
.recording-controls, .session-controls {
margin-top:0px;
@ -86,20 +133,6 @@
line-height:19px;
}
.session-controls {
&.ended {
background-color: #471f18;
.play-button {
display:none;
}
}
&.inprogress {
background-color: #4C742E;
}
}
.details {
color:#ED3618;
}

View File

@ -1,3 +1,5 @@
@import "client/common.css.scss";
.feed-entry .recording-controls, .feed-entry .session-controls, .landing-details .recording-controls {
margin-top:0px;
margin-bottom:5px;
@ -5,7 +7,19 @@
width:98%;
position:relative;
text-align:center;
}
.landing-details .recording-controls, .landing-details .recording-controls {
background-color:#242323;
@include border_box_sizing;
width:100%;
.session-status {
float:left;
margin-left:20px;
}
}
.recording-position {
@ -52,7 +66,7 @@
font-family:Arial, Helvetica, sans-serif;
display:inline-block;
font-size:18px;
position:absolute;
float:right;
top:3px;
right:4px;
}

View File

@ -5,6 +5,7 @@
*= require easydropdown_jk
*= require client/screen_common
*= require client/content
*= require web/audioWidgets
*= require client/notify
*= require client/ftue
*= require client/user_dropdown

View File

@ -14,202 +14,6 @@ body.web {
}
}
.session-controls {
margin-top: 15px;
padding: 3px 5px 3px 10px;
width: 93%;
min-width: 200px;
background-color: #242323;
position: relative;
font-size: 13px;
text-align: center;
@include border_box_sizing;
height: 36px;
}
.recording-controls {
margin-top: 15px;
padding: 3px 5px 3px 10px;
width: 93%;
min-width: 200px;
background-color: #242323;
position: relative;
font-size: 13px;
text-align: center;
@include border_box_sizing;
height: 36px;
}
.feed-entry {
position:relative;
display:block;
white-space:nowrap;
min-width:700px;
border-bottom:solid 1px #666;
max-height:74px;
overflow:hidden;
margin-top:20px;
&:nth-child(1) {
margin-top:0;
}
/**
&.animate-down {
-webkit-transition: max-height height 2s;
transition: max-height height 2s;
-moz-transition: max-height height 2s;
-o-transition: max-height height 2s;
-ms-transition: max-height height 2s;
}
&.animate-up {
-webkit-transition: max-height height .4s;
transition: max-height height .4s;
-moz-transition: max-height height .4s;
-o-transition: max-height height .4s;
-ms-transition: max-height height .4s;
}
*/
.session-status {
float:left;
font-size:18px;
}
.inprogress {
.session-status {
font-size: 15px;
color: #cccc00;
margin-left:20px;
}
}
.recording-current {
top:8px;
}
.session-duration {
top:8px;
}
.recording-controls, .session-controls {
margin-top:0px;
margin-bottom:5px;
padding:8px 5px 8px 10px;
width:98%;
line-height:19px;
}
.session-controls {
&.ended {
background-color: #471f18;
.play-button {
display:none;
}
}
&.inprogress {
background-color: #4C742E;
}
}
.details {
color:#ED3618;
}
.avatar-small {
@include content_box_sizing;
margin-top:0px;
margin-left:0px;
}
.title {
font-size:16px;
color:#999;
margin-bottom:3px;
}
.artist {
font-size:12px;
font-weight:bold;
color:#ccc;
margin-bottom:10px;
overflow: hidden;
white-space: nowrap;
}
.name {
font-weight:bold;
font-size:14px;
}
.description {
font-size:12px;
white-space:normal;
line-height:14px;
overflow:hidden;
text-overflow:ellipsis;
height:60px;
}
.feed-details {
vertical-align:middle;
img {
vertical-align:middle;
}
}
.play-count {
margin-right:10px;
}
.comment-count {
margin-right:10px;
}
.like-count {
margin-right:10px;
}
.musicians {
margin-top:10px;
font-size:11px;
}
.musicians td {
border-right:none;
border-top:none;
padding:3px;
vertical-align:middle;
}
.musicians a {
color:#fff;
text-decoration:none;
}
.avatar-tiny {
float:left;
padding:1px;
width:24px;
height:24px;
background-color:#ed3618;
-webkit-border-radius:12px;
-moz-border-radius:12px;
border-radius:12px;
}
.avatar-tiny img {
width: 24px;
height: 24px;
-webkit-border-radius:12px;
-moz-border-radius:12px;
border-radius:12px;
}
}
.buzz {
width: 300px;
position:relative;

View File

@ -7,7 +7,7 @@ module FeedsHelper
image_tag resolve_avatarables(music_session_history.band, music_session_history.user)
end
def session_duration(music_session_history, options)
def session_duration(music_session_history, options={})
if music_session_history.session_removed_at.nil?
duration(Time.now - music_session_history.created_at, options)
else
@ -34,7 +34,7 @@ module FeedsHelper
image_tag resolve_avatarables(recording.band, recording.owner)
end
def recording_duration(recording, options)
def recording_duration(recording, options={})
duration(recording.duration, options)
end

View File

@ -51,26 +51,17 @@
<% end %>
<br clear="all" />
<div class="w100">
<div class="recording-controls">
<% if !@music_session.music_session.nil? && !@music_session.music_session.mount.blank? %>
<a id="btnPlayPause" class="left mr20">
<%= image_tag "content/icon_playbutton.png", {:id => "imgPlayPause", :width => 20, :height => 20, :alt => ""} %>
</a>
<% end %>
<% if @music_session.session_removed_at.blank? %>
<div class="session-status">SESSION IN PROGRESS</div>
<div class="recording-current"></div>
<audio controls preload="none" style="display:none;">
<% unless @music_session.music_session.nil? || @music_session.music_session.mount.blank? %>
<div class="recording-controls <%= @music_session.is_over? ? 'ended' : 'inprogress' %>" data-music-session="<%=@music_session.id %>">
<a class="left play-button" href="#">
<%= image_tag 'content/icon_playbutton.png', width:20, height:20, class:'play-icon' %>
<% if @music_session.music_session && @music_session.music_session.mount %>
<audio preload="none">
<source src="<%= @music_session.music_session.mount.url %>" type="<%= @music_session.music_session.mount.resolve_string(:mime_type) %>">
<% end %>
</audio>
<% if @music_session.music_session.nil? || @music_session.music_session.mount.blank? %>
<div>NO AUDIO AVAILABLE</div>
</audio>
<% end %>
<% else %>
<div class="session-status-ended">LIVE SESSION ENDED</div>
<% end %>
</a>
<div class="session-status"><%= @music_session.is_over? ? 'SESSION ENDED' : 'LIVE SESSION IN PROGRESS' %></div>
<%= session_duration(@music_session, class: 'session-duration tick-duration recording-current', 'data-created-at' => @music_session.created_at.to_i) %>
</div>
<div class="left white"><%= @music_session.genres.split('|').first.capitalize %></div>
@ -113,5 +104,6 @@
$(function () {
var showMusicSession = new JK.ShowMusicSession(JK.app);
showMusicSession.initialize("<%= @music_session.id %>");
});
</script>
<% end %>

View File

@ -25,7 +25,7 @@
.session-status
= feed_item.is_over? ? 'SESSION ENDED' : 'SESSION IN PROGRESS'
/ current playback time
= session_duration(feed_item, class: 'session-duration recording-current', 'data-created-at' => feed_item.created_at.to_i)
= session_duration(feed_item, class: 'session-duration tick-duration recording-current', 'data-created-at' => feed_item.created_at.to_i)
/ end recording play controls
/ genre and social
.left.small

View File

@ -20,7 +20,11 @@
.recording-controls
/ play button
%a.left.play-button{:href => "#"}
= image_tag 'content/icon_playbutton.png', width:20, height:20
= image_tag 'content/icon_playbutton.png', width:20, height:20, class:'play-icon'
- if feed_item.has_mix?
%audio{preload: 'none'}
%source{src: claimed_recording_download_url(feed_item.candidate_claimed_recording.id, 'mp3'), type:'audio/mpeg'}
%source{src: claimed_recording_download_url(feed_item.candidate_claimed_recording.id, 'ogg'), type:'audio/ogg'}
/ playback position
.recording-position
/ start time
@ -30,11 +34,12 @@
.recording-slider
= image_tag 'content/slider_playcontrols.png', width:5, height:16
/ end time
.recording-time 4:59
.recording-time.recording-duration
= recording_duration(feed_item)
/ end playback position
/ current playback time
.recording-current
1:23
0:00
/ end recording play controls
/ genre and social
.left.small