* VRFS-1047 - broadcasts can be listened to (but very raw). VRFS-1257 - adding back in listen_in page for admin only

This commit is contained in:
Seth Call 2014-02-27 18:38:02 +00:00
parent 7c99c44eaf
commit aaef11add4
17 changed files with 283 additions and 22 deletions

View File

@ -41,6 +41,7 @@ gem 'resque-failed-job-mailer' #, :path => "/Users/seth/workspace/resque_failed_
gem 'resque-lonely_job', '~> 1.0.0'
gem 'oj'
gem 'builder'
gem 'fog'
group :test do
gem 'simplecov', '~> 0.7.1'

View File

@ -110,7 +110,7 @@ module JamRuby
def listener_add
with_lock do
sourced_needs_changing_at = Time.now if listeners == 0
self.sourced_needs_changing_at = Time.now if listeners == 0
# this is completely unsafe without that 'with_lock' statement above
self.listeners = self.listeners + 1
@ -126,7 +126,7 @@ module JamRuby
end
with_lock do
sourced_needs_changing_at = Time.now if listeners == 1
self.sourced_needs_changing_at = Time.now if listeners == 1
# this is completely unsafe without that 'with_lock' statement above
self.listeners = self.listeners - 1

View File

@ -8,12 +8,31 @@
var $feedItem = $parentElement;
var $description = $('.description', $feedItem)
var $musicians = $('.musician-detail', $feedItem)
var $controls = $('.session-controls', $feedItem);
var playing = false;
var toggledOpen = false;
var toggledOpen = false;
if(!$feedItem.is('.feed-entry')) {
throw "$parentElement must be a .feed-entry"
}
function togglePlay() {
if(playing) {
var img = $('.play-icon', $(this));
img.attr('src', '/assets/content/icon_playbutton.png');
$controls.trigger('pause.listenBroadcast');
}
else {
var img = $('.play-icon', $(this));
img.attr('src', '/assets/content/icon_pausebutton.png');
$controls.trigger('play.listenBroadcast');
}
playing = !playing;
return false;
}
function toggleDetails() {
if(toggledOpen) {
@ -39,11 +58,13 @@
function events() {
$('.details', $feedItem).click(toggleDetails);
$('.details-arrow', $feedItem).click(toggleDetails);
$('.play-button', $feedItem).click(togglePlay);
}
function initialize() {
$('.timeago', $feedItem).timeago();
$('.dotdotdot', $feedItem).dotdotdot();
$controls.listenBroadcast();
context.JK.prettyPrintElements($('time.duration', $feedItem));
context.JK.setInstrumentAssetPath($('.instrument-icon', $feedItem));

View File

@ -0,0 +1,162 @@
(function(context, $) {
"use strict";
context.JK = context.JK || {};
// the purpose of this code is to simply 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
// $parentElement: the parent element needs to contain one audio element; this will take control of it.
// pass in music_session as a 'data-music-session' attribute on the $parentElement
// this will also interact with any REST APIs needed to
context.JK.ListenBroadcast = function($parentElement, options){
var logger = context.JK.logger;
var rest = context.JK.Rest();
var $parent = $parentElement;
var $audio = null;
var audioDomElement = null;
var musicSessionId = null;
var isPlaying = false; // tracks if the stream is actually playing
function play(e) {
if(e) {
e.preventDefault();
e.stopPropagation();
}
if(!audioDomElement) throw "no audio element supplied; the user should not be able to attempt a play"
audioDomElement.play();
}
function pause(e) {
if(e) {
e.preventDefault();
e.stopPropagation();
}
if (!audioDomElement) throw "no audio element supplied; the user should not be able to attempt a pause"
audioDomElement.pause();
}
function onPlay() {
logger.debug("onplay", arguments);
isPlaying = true;
}
function onPlaying() {
logger.debug("onplaying", arguments);
isPlaying = true;
}
function onPause() {
logger.debug("onpause", arguments);
isPlaying = false;
}
function onError() {
logger.debug("onerror", arguments);
}
function onEnded() {
logger.debug("onended", arguments);
}
function onEmptied() {
logger.debug("onemptied", arguments);
}
function onAbort() {
logger.debug("onabort", arguments);
}
function onStalled() {
logger.debug("onstalled", arguments);
// fires in Chrome on page load
}
function onSuspend() {
logger.debug("onsuspend", arguments);
// fires in FF on page load
}
function onTimeUpdate() {
//logger.debug("ontimeupdate", arguments);
}
function onProgress() {
//logger.debug("onprogress", arguments);
}
function initialize() {
musicSessionId = $parent.attr('data-music-session');
if(!musicSessionId) throw "data-music-session must be specified on $parentElement";
$audio = $('audio', $parent);
if($audio.length == 0) {
logger.debug("listen_broadcast: no audio element. deactivating")
return;
}
if($audio.length > 1) {
throw "more than one <audio> element found";
}
audioDomElement = $audio.get(0);
function getAllEvents(element) {
var result = [];
for (var key in element) {
if (key.indexOf('on') === 0) {
result.push(key);
}
}
return result.join(' ');
}
console.log("ALL events names: " + getAllEvents(audioDomElement))
$audio.bind(getAllEvents(audioDomElement), function(e) { console.log("ALL EVENT:", arguments) });
$audio.bind('*', function() {alert('works')});
$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('load', function() { console.log("load", arguments)})
$parent.bind('play.listenBroadcast', play);
$parent.bind('pause.listenBroadcast', pause);
}
initialize();
this.play = play;
this.pause = pause;
return this;
}
$.fn.listenBroadcast = function(options) {
new context.JK.ListenBroadcast(this, options);
}
})(window, jQuery);

View File

@ -31,7 +31,7 @@
var playbackControls = null;
var promptLeave = false;
var rest = JK.Rest();
var rest = context.JK.Rest();
var RENDER_SESSION_DELAY = 750; // When I need to render a session, I have to wait a bit for the mixers to be there.

View File

@ -294,7 +294,6 @@
if(!$element.is('img')) { throw "expected to receive an <img> in setInstrumentAssetPath" }
var instrument = $element.attr('instrument-id');
if(!instrument) { throw "expect there to be an instrument defined in setInstrumentAssetPath" }
$element.attr('src', context.JK.getInstrumentIcon24(instrument))
})

View File

@ -10,6 +10,7 @@
//= require jquery.mousewheel-3.1.9
//= require jquery.timeago
//= require jquery.dotdotdot
//= require jquery.listenbroadcast
//= require AAA_Log
//= require AAC_underscore
//= require globals

View File

@ -122,6 +122,9 @@
float:left;
font-size:18px;
margin-top:12px;
.friend-name-label {
}
}
li .friend-status {

View File

@ -11,6 +11,10 @@ class SpikesController < ApplicationController
def listen_in
if !current_user.admin
raise PermissionError "must be administrator"
end
#as_musician = false is the critical search criteria for sessions to list correctly
@music_sessions = MusicSession.index(current_user, as_musician: false)

View File

@ -19,6 +19,13 @@ module FeedsHelper
music_session_history.description
end
# grabs 1st genre
def session_genre(music_session_history)
genres_array = music_session_history.genres.nil? ? [] : music_session_history.genres.split(MusicSessionHistory::SEPARATOR)
genre = genres_array.length > 0 ? Genre.find_by_id(genres_array[0]) : nil
genre.nil? ? '' : genre.description
end
def recording_artist_name(recording)
(recording.band.nil? ? nil : recording.band.name) || recording.candidate_claimed_recording.user.name
end
@ -39,4 +46,8 @@ module FeedsHelper
recording.candidate_claimed_recording.description
end
def recording_genre(recording)
recording.candidate_claimed_recording.genre.description
end
end

View File

@ -151,7 +151,7 @@
<img src="{avatar}"/>
</div>
<div class="track-instrument {preMasteredClass}">
<img src="/assets/{instrumentIcon}" width="45" height="45"/>
<img src="{instrumentIcon}" width="45" height="45"/>
</div>
<div class="track-gain" mixer-id="{mixerId}"></div>
<!--

View File

@ -173,7 +173,7 @@
<li class="{cssClass}">
<div class="avatar-small" user-id="{userId}" hoveraction="{hoverAction}"><img src="{avatar_url}" /></div>
<div class="friend-name" user-id="{userId}" hoveraction="{hoverAction}">
{userName}<br/>
<span class="friend-name-label">{userName}</span><br/>
<span class="friend-status">
{status} {extra_info}
</span>

View File

@ -1,4 +1,3 @@
= puts "feedededededeedde #{feed_item.inspect}"
- if feed_item.music_session_history
= render :partial => "feed_music_session", locals: { feed_item: feed_item.music_session_history }
- else

View File

@ -15,26 +15,33 @@
/ timeline and controls
.right.w40
/ recording play controls
.session-controls{class: (feed_item.is_over? ? 'ended' : 'inprogress')}
.session-controls{ class: (feed_item.is_over? ? 'ended' : 'inprogress'), 'data-music-session' => feed_item.id }
/ session status
%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.music_session && feed_item.music_session.mount
%audio{preload: 'none'}
%source{src: feed_item.music_session.mount.url, type: feed_item.music_session.mount.resolve_string(:mime_type)}
.session-status
= feed_item.is_over? ? 'SESSION ENDED' : 'SESSION IN PROGRESS'
/ current playback time
= session_duration(feed_item, class: 'recording-current')
/ end recording play controls
/ genre and social
.left.small Pop
.left.small
= session_genre(feed_item)
.right.small.feed-details
%span.play-count
%span.plays 80
%span.plays
= feed_item.play_count
= image_tag 'content/icon_arrow.png', :height => "12", :width => "7"
%span.comment-count
%span.comments 12
%span.comments
= feed_item.comment_count
= image_tag 'content/icon_comment.png', :height => "12", :width => "13"
%span.like-count
%span.likes 35
%span.likes
= feed_item.like_count
= image_tag 'content/icon_like.png', :height => "12", :width => "12"
%a.details{:href => "#"} Details
%a.details-arrow.arrow-down-orange{:href => "#"}
@ -53,8 +60,12 @@
= "#{user.first_name} #{user.last_name}"
%td
.nowrap
- user.total_instruments.split('|').uniq.each do |instrument_id|
%img.instrument-icon{'instrument-id' =>instrument_id, height:24, width:24}
- if user.total_instruments
- user.total_instruments.split('|').uniq.each do |instrument_id|
%img.instrument-icon{'instrument-id' =>instrument_id, height:24, width:24}
- else
%img.instrument-icon{'instrument-id' =>'default', height:24, width:24}
%br{:clear => "all"}/
%br/

View File

@ -37,16 +37,20 @@
1:23
/ end recording play controls
/ genre and social
.left.small Blues
.left.small
= recording_genre(feed_item)
.right.small.feed-details
%span.play-count
%span.plays 80
%span.plays
= feed_item.play_count
= image_tag 'content/icon_arrow.png', :height => "12", :width => "7"
%span.comment-count
%span.comments 12
%span.comments
= feed_item.comment_count
= image_tag 'content/icon_comment.png', :height => "12", :width => "13"
%span.like-count
%span.likes 35
%span.likes
= feed_item.like_count
= image_tag 'content/icon_like.png', :height => "12", :width => "12"
%a.details{:href => "#"} Details
%a.details-arrow.arrow-down-orange{:href => "#"}

View File

@ -60,6 +60,10 @@ SampleApp::Application.routes.draw do
match '/gmail_contacts', to: 'gmail#gmail_contacts'
# temporarily allow for debugging
match '/listen_in', to: 'spikes#listen_in'
# embed resque-web if this is development mode
if Rails.env == "development"
require 'resque/server'
@ -69,7 +73,6 @@ SampleApp::Application.routes.draw do
# route to spike controller (proof-of-concepts)
match '/facebook_invite', to: 'spikes#facebook_invite'
match '/listen_in', to: 'spikes#listen_in'
# junk pages
match '/help', to: 'static_pages#help'

View File

@ -11,6 +11,10 @@ describe "Welcome", :js => true, :type => :feature, :capybara_feature => true d
end
before(:each) do
Feed.delete_all
MusicSessionHistory.delete_all
Recording.delete_all
page.driver.headers = { 'User-Agent' => ' JamKazam ' }
visit "/"
find('h1', text: 'Play music together over the Internet as if in the same room')
@ -148,13 +152,51 @@ describe "Welcome", :js => true, :type => :feature, :capybara_feature => true d
end
describe "feed" do
it "typical feed" do
it "data" do
claimedRecording1 = FactoryGirl.create(:claimed_recording)
musicSessionHistory1 = claimedRecording1.recording.music_session.music_session_history
visit "/"
find('h1', text: 'Play music together over the Internet as if in the same room')
find('.feed-entry.music-session-history-entry .description', text: musicSessionHistory1.description)
find('.feed-entry.music-session-history-entry .session-status', text: 'SESSION IN PROGRESS')
find('.feed-entry.music-session-history-entry .session-controls.inprogress', text: 'SESSION IN PROGRESS')
find('.feed-entry.music-session-history-entry .artist', text: musicSessionHistory1.user.name)
should_not have_selector('.feed-entry.music-session-history-entry .musician-detail')
find('.feed-entry.recording-entry .name', text: claimedRecording1.name)
find('.feed-entry.recording-entry .description', text: claimedRecording1.description)
find('.feed-entry.recording-entry .title', text: 'RECORDING')
find('.feed-entry.recording-entry .artist', text: claimedRecording1.user.name)
should_not have_selector('.feed-entry.recording-entry .musician-detail')
# try to hide the recording
claimedRecording1.is_public = false
claimedRecording1.save!
visit "/"
find('h1', text: 'Play music together over the Internet as if in the same room')
find('.feed-entry.music-session-history-entry .description', text: musicSessionHistory1.description)
should_not have_selector('.feed-entry.recording-entry')
# try to mess with the music session history by removing all user histories (which makes it a bit invalid)
# but we really don't want the front page to ever crash if we can help it
musicSessionHistory1.music_session_user_histories.delete_all
musicSessionHistory1.reload
musicSessionHistory1.music_session_user_histories.length.should == 0
visit "/"
find('h1', text: 'Play music together over the Internet as if in the same room')
find('.feed-entry.music-session-history-entry .description', text: musicSessionHistory1.description)
# try to hide the music session
musicSessionHistory1.fan_access = false
musicSessionHistory1.save!
visit "/"
find('h1', text: 'Play music together over the Internet as if in the same room')
should_not have_selector('.feed-entry.music-session-history-entry')
end
end
end