Merge with develop
This commit is contained in:
parent
d314c3327c
commit
5396e66c67
|
|
@ -26,6 +26,7 @@ ActiveAdmin.register JamRuby::JamTrack, :as => 'JamTracks' do
|
|||
column :id
|
||||
column :name
|
||||
column :description
|
||||
column :version
|
||||
column :initial_play_silence
|
||||
column :time_signature
|
||||
column :status
|
||||
|
|
|
|||
|
|
@ -7,7 +7,9 @@
|
|||
| JamTrack should only be made available (to end users) if all its sub-component are in place:
|
||||
= f.input :available, as: :boolean
|
||||
= f.input :description, :input_html => { :rows=>5, :maxlength=>1000 }
|
||||
= f.input :initial_play_silence, :label => 'Initial Play Silence (seconds)'
|
||||
= f.input :plan_code, :label=>'Recurly Plan Code', :required=>true, :hint => 'Must match plan code in Recurly'
|
||||
= f.input :version, :label => 'Version', :hint => 'Increment this value whenever you invalidate (update) the definition of this JamTrack'
|
||||
//= f.input :initial_play_silence, :label => 'Initial Play Silence (seconds)'
|
||||
= f.input :time_signature, collection: JamRuby::JamTrack::TIME_SIGNATURES, include_blank: false
|
||||
= f.input :status, collection: JamRuby::JamTrack::STATUS, include_blank: false
|
||||
= f.input :recording_type, collection: JamRuby::JamTrack::RECORDING_TYPE, include_blank: false
|
||||
|
|
@ -24,8 +26,9 @@
|
|||
= f.input :reproduction_royalty_amount, :required=>true, :input_html=>{type:'numeric'}
|
||||
= f.input :licensor_royalty_amount, :required=>true, :input_html=>{type:'numeric'}
|
||||
= f.input :pro_royalty_amount, :required=>true, :input_html=>{type:'numeric'}
|
||||
= f.input :plan_code, :label=>'Recurly Plan Code', :required=>true
|
||||
= f.input :url, :as => :file, :label => 'Audio File'
|
||||
= f.input :jmep_text, :as => :text, :label => "JMEP Text", :input_html => {:rows => 5 }
|
||||
= f.input :jmep_json, :as => :text, :label => "JMEP Json", :input_html => {:rows => 5, :readonly=>true }, :hint => 'readonly'
|
||||
|
||||
= f.semantic_fields_for :jam_track_tracks do |track|
|
||||
= render 'jam_track_track_fields', f: track
|
||||
|
|
|
|||
|
|
@ -147,5 +147,8 @@ module JamAdmin
|
|||
config.influxdb_hosts = ["localhost"]
|
||||
config.influxdb_port = 8086
|
||||
config.influxdb_ignored_environments = ENV["INFLUXDB_ENABLED"] == '1' ? ['test', 'cucumber'] : ['test', 'cucumber', 'development']
|
||||
|
||||
config.jamtracks_dir = ENV['JAMTRACKS_DIR'] || File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "..", "jamtracks"))
|
||||
config.jmep_dir = ENV['JMEP_DIR'] || File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "..", "jmep"))
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
class JamRuby::JamTrack
|
||||
|
||||
# add a custom validation
|
||||
|
||||
before_save :jmep_json_generate
|
||||
validate :jmep_text_validate
|
||||
|
||||
def jmep_text_validate
|
||||
begin
|
||||
JmepManager.execute(self.jmep_text)
|
||||
rescue ArgumentError => err
|
||||
errors.add(:jmep_text, err.to_s)
|
||||
end
|
||||
end
|
||||
|
||||
def jmep_json_generate
|
||||
begin
|
||||
self[:jmep_json] = JmepManager.execute(self.jmep_text)
|
||||
rescue ArgumentError => err
|
||||
#errors.add(:jmep_text, err.to_s)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
2
build
2
build
|
|
@ -66,7 +66,7 @@ DEB_SERVER=http://localhost:9010/apt-`uname -p`
|
|||
GEM_SERVER=http://localhost:9000/gems
|
||||
|
||||
# if still going, then push all debs up
|
||||
if [[ "$GIT_BRANCH" == *develop* || "$GIT_BRANCH" == *master* || "$GIT_BRANCH" == *release* ]]; then
|
||||
if [[ "$GIT_BRANCH" == *develop* || "$GIT_BRANCH" == *master* || "$GIT_BRANCH" == *release* || "$GIT_BRANCH" == *feature* || "$GIT_BRANCH" == *hotfix* ]]; then
|
||||
|
||||
echo ""
|
||||
echo "PUSHING DB ARTIFACTS"
|
||||
|
|
|
|||
|
|
@ -255,3 +255,6 @@ user_syncs_include_backing_tracks.sql
|
|||
remove_bpm_from_jamtracks.sql
|
||||
add_jam_track_bitrates.sql
|
||||
widen_user_authorization_token.sql
|
||||
jam_track_version.sql
|
||||
recorded_jam_track_tracks.sql
|
||||
jam_track_jmep_data.sql
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE jam_tracks ADD COLUMN jmep_text VARCHAR;
|
||||
ALTER TABLE jam_tracks ADD COLUMN jmep_json JSON;
|
||||
|
|
@ -0,0 +1 @@
|
|||
ALTER TABLE jam_tracks ADD COLUMN version VARCHAR NOT NULL DEFAULT 0;
|
||||
|
|
@ -1,15 +1,15 @@
|
|||
ALTER TABLE recordings ADD COLUMN jam_track_id VARCHAR(64) REFERENCES jam_tracks(id);
|
||||
ALTER TABLE recordings ADD COLUMN jam_track_id BIGINT REFERENCES jam_tracks(id);
|
||||
ALTER TABLE recordings ADD COLUMN jam_track_initiator_id VARCHAR(64) REFERENCES users(id);
|
||||
|
||||
CREATE TABLE recorded_jam_track_tracks (
|
||||
id BIGINT PRIMARY KEY,
|
||||
user_id VARCHAR(64) REFERENCES users(id) ON DELETE CASCADE,
|
||||
jam_track_track_id VARCHAR(64),
|
||||
recording_id VARCHAR(64) NOT NULL,
|
||||
user_id VARCHAR(64) NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
jam_track_track_id VARCHAR(64) REFERENCES jam_track_tracks(id) NOT NULL,
|
||||
recording_id VARCHAR(64) REFERENCES recordings(id) NOT NULL,
|
||||
discard BOOLEAN,
|
||||
timeline JSON,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
ALTER TABLE recorded_jam_tracks ALTER COLUMN id SET DEFAULT nextval('tracks_next_tracker_seq');
|
||||
ALTER TABLE recorded_jam_track_tracks ALTER COLUMN id SET DEFAULT nextval('tracks_next_tracker_seq');
|
||||
|
|
|
|||
|
|
@ -139,6 +139,7 @@ require "jam_ruby/models/recorded_backing_track_observer"
|
|||
require "jam_ruby/models/recorded_track"
|
||||
require "jam_ruby/models/recorded_track_observer"
|
||||
require "jam_ruby/models/recorded_video"
|
||||
require "jam_ruby/models/recorded_jam_track_track"
|
||||
require "jam_ruby/models/quick_mix"
|
||||
require "jam_ruby/models/quick_mix_observer"
|
||||
require "jam_ruby/models/share_token"
|
||||
|
|
@ -204,6 +205,7 @@ require "jam_ruby/models/user_sync"
|
|||
require "jam_ruby/models/video_source"
|
||||
require "jam_ruby/models/text_message"
|
||||
require "jam_ruby/jam_tracks_manager"
|
||||
require "jam_ruby/jmep_manager"
|
||||
|
||||
include Jampb
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ module JamRuby
|
|||
|
||||
def save_jam_track_right_jkz(jam_track_right, bitrate=48)
|
||||
jam_track = jam_track_right.jam_track
|
||||
#py_root = File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "..", "..", "jamtracks"))
|
||||
py_root = APP_CONFIG.jamtracks_dir
|
||||
Dir.mktmpdir do |tmp_dir|
|
||||
jam_file_opts=""
|
||||
|
|
@ -42,10 +41,11 @@ module JamRuby
|
|||
title=jam_track.name
|
||||
output_jkz=File.join(tmp_dir, "#{title.parameterize}.jkz")
|
||||
py_file = File.join(py_root, "jkcreate.py")
|
||||
version = jam_track.version
|
||||
@@log.info "Executing python source in #{py_file}, outputting to #{tmp_dir} (#{output_jkz})"
|
||||
|
||||
# From http://stackoverflow.com/questions/690151/getting-output-of-system-calls-in-ruby/5970819#5970819:
|
||||
cli = "python #{py_file} -D -k #{sku} -p #{tmp_dir}/pkey.pem -s #{tmp_dir}/skey.pem #{jam_file_opts} -o #{output_jkz} -t '#{title}'"
|
||||
cli = "python #{py_file} -D -k #{sku} -p #{tmp_dir}/pkey.pem -s #{tmp_dir}/skey.pem #{jam_file_opts} -o #{output_jkz} -t '#{title}' -V '#{version}'"
|
||||
Open3.popen3(cli) do |stdin, stdout, stderr, wait_thr|
|
||||
pid = wait_thr.pid
|
||||
exit_status = wait_thr.value
|
||||
|
|
|
|||
|
|
@ -0,0 +1,55 @@
|
|||
require 'json'
|
||||
require 'tempfile'
|
||||
require 'open3'
|
||||
require 'fileutils'
|
||||
require 'open-uri'
|
||||
|
||||
module JamRuby
|
||||
|
||||
# Interact with external python tools to create jmep json
|
||||
class JmepManager
|
||||
|
||||
@@log = Logging.logger[JmepManager]
|
||||
|
||||
class << self
|
||||
|
||||
def execute(jmep_text)
|
||||
|
||||
json = nil
|
||||
|
||||
if jmep_text.blank?
|
||||
return nil
|
||||
end
|
||||
|
||||
py_root = APP_CONFIG.jmep_dir
|
||||
Dir.mktmpdir do |tmp_dir|
|
||||
|
||||
output_json = File.join(tmp_dir, "jmep.json")
|
||||
input_text = File.join(tmp_dir, "jmep.txt")
|
||||
|
||||
# put JMEP text into input file
|
||||
File.open(input_text, 'w') { |file| file.write(jmep_text) }
|
||||
|
||||
py_file = File.join(py_root, "jmepgen.py")
|
||||
@@log.info "Executing python source in #{py_file}, outputting to #{output_json})"
|
||||
|
||||
# From http://stackoverflow.com/questions/690151/getting-output-of-system-calls-in-ruby/5970819#5970819:
|
||||
cli = "python #{py_file} -i '#{input_text}' -o '#{output_json}'"
|
||||
Open3.popen3(cli) do |stdin, stdout, stderr, wait_thr|
|
||||
pid = wait_thr.pid
|
||||
exit_status = wait_thr.value
|
||||
err = stderr.read(1000)
|
||||
out = stdout.read(1000)
|
||||
|
||||
raise ArgumentError, "#{out} #{err}" if exit_status != 0
|
||||
|
||||
json = File.read(output_json)
|
||||
end
|
||||
end
|
||||
|
||||
json
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -16,7 +16,7 @@ module JamRuby
|
|||
:original_artist, :songwriter, :publisher, :licensor, :licensor_id, :pro, :genre, :genre_id, :sales_region, :price,
|
||||
:reproduction_royalty, :public_performance_royalty, :reproduction_royalty_amount,
|
||||
:licensor_royalty_amount, :pro_royalty_amount, :plan_code, :initial_play_silence, :jam_track_tracks_attributes,
|
||||
:jam_track_tap_ins_attributes, :available, as: :admin
|
||||
:jam_track_tap_ins_attributes, :available, :version, :jmep_json, :jmep_text, as: :admin
|
||||
|
||||
validates :name, presence: true, uniqueness: true, length: {maximum: 200}
|
||||
validates :description, length: {maximum: 1000}
|
||||
|
|
@ -30,6 +30,7 @@ module JamRuby
|
|||
validates :sales_region, inclusion: {in: [nil] + SALES_REGION}
|
||||
validates_format_of :price, with: /^\d+\.*\d{0,2}$/
|
||||
validates :initial_play_silence, numericality: true, :allow_nil => true
|
||||
validates :version, presence: true
|
||||
|
||||
validates :reproduction_royalty, inclusion: {in: [nil, true, false]}
|
||||
validates :public_performance_royalty, inclusion: {in: [nil, true, false]}
|
||||
|
|
@ -50,6 +51,8 @@ module JamRuby
|
|||
|
||||
has_many :playing_sessions, :class_name => "JamRuby::ActiveMusicSession"
|
||||
|
||||
has_many :recordings, :class_name => "JamRuby::Recording"
|
||||
|
||||
accepts_nested_attributes_for :jam_track_tracks, allow_destroy: true
|
||||
accepts_nested_attributes_for :jam_track_tap_ins, allow_destroy: true
|
||||
|
||||
|
|
@ -156,6 +159,7 @@ module JamRuby
|
|||
def sanitize_active_admin
|
||||
self.genre_id = nil if self.genre_id == ''
|
||||
self.licensor_id = nil if self.licensor_id == ''
|
||||
self.jmep_json = nil if self.jmep_json = ''
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -143,8 +143,6 @@ module JamRuby
|
|||
state = nil
|
||||
if signed
|
||||
state = 'SIGNED'
|
||||
elsif error_count > 0
|
||||
state = 'ERROR'
|
||||
elsif signing_started_at
|
||||
if Time.now - signing_started_at > APP_CONFIG.signing_job_run_max_time
|
||||
state = 'SIGNING_TIMEOUT'
|
||||
|
|
@ -157,6 +155,8 @@ module JamRuby
|
|||
else
|
||||
state = 'QUEUED'
|
||||
end
|
||||
elsif error_count > 0
|
||||
state = 'ERROR'
|
||||
else
|
||||
state = 'QUIET' # needs to be poked to go build
|
||||
end
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@ module JamRuby
|
|||
belongs_to :instrument, class_name: "JamRuby::Instrument"
|
||||
belongs_to :jam_track, class_name: "JamRuby::JamTrack"
|
||||
|
||||
has_many :recorded_jam_track_tracks, :class_name => "JamRuby::RecordedJamTrackTrack", :foreign_key => :jam_track_track_id, :dependent => :destroy
|
||||
|
||||
# create storage directory that will house this jam_track, as well as
|
||||
def store_dir
|
||||
"#{jam_track.store_dir}/tracks"
|
||||
|
|
|
|||
|
|
@ -141,12 +141,35 @@ module JamRuby
|
|||
|
||||
recording.recorded_tracks.each do |recorded_track|
|
||||
manifest["files"] << { "filename" => recorded_track.sign_url(one_day), "codec" => "vorbis", "offset" => 0 }
|
||||
mix_params << { "level" => 100, "balance" => 0 }
|
||||
mix_params << { "level" => 1.0, "balance" => 0 }
|
||||
end
|
||||
|
||||
recording.recorded_backing_tracks.each do |recorded_backing_track|
|
||||
manifest["files"] << { "filename" => recorded_backing_track.sign_url(one_day), "codec" => "vorbis", "offset" => 0 }
|
||||
mix_params << { "level" => 100, "balance" => 0 }
|
||||
mix_params << { "level" => 1.0, "balance" => 0 }
|
||||
end
|
||||
|
||||
recording.recorded_jam_track_tracks.each do |recorded_jam_track_track|
|
||||
manifest["files"] << { "filename" => recorded_jam_track_track.jam_track_track.sign_url(one_day), "codec" => "vorbis", "offset" => 0 }
|
||||
# let's look for level info from the client
|
||||
level = 1.0 # default value - means no effect
|
||||
if recorded_jam_track_track.timeline
|
||||
|
||||
timeline_data = JSON.parse(recorded_jam_track_track.timeline)
|
||||
|
||||
# always take the 1st entry for now
|
||||
first = timeline_data[0]
|
||||
|
||||
if first["mute"]
|
||||
# mute equates to no noise
|
||||
level = 0.0
|
||||
else
|
||||
# otherwise grab the left channel...
|
||||
level = first["vol_l"]
|
||||
end
|
||||
end
|
||||
|
||||
mix_params << { "level" => level, "balance" => 0 }
|
||||
end
|
||||
|
||||
manifest["timeline"] << { "timestamp" => 0, "mix" => mix_params }
|
||||
|
|
|
|||
|
|
@ -10,11 +10,11 @@ module JamRuby
|
|||
validates :jam_track_track, presence:true
|
||||
|
||||
def self.create_from_jam_track_track(jam_track_track, recording)
|
||||
recorded_backing_track = self.new
|
||||
recorded_backing_track.recording = recording
|
||||
recorded_backing_track.jam_track_track = jam_track_track
|
||||
recorded_backing_track.save
|
||||
recorded_backing_track
|
||||
recorded_jam_track_track = self.new
|
||||
recorded_jam_track_track.recording = recording
|
||||
recorded_jam_track_track.jam_track_track = jam_track_track
|
||||
recorded_jam_track_track.save
|
||||
recorded_jam_track_track
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ module JamRuby
|
|||
has_many :recorded_tracks, :class_name => "JamRuby::RecordedTrack", :foreign_key => :recording_id, :dependent => :destroy
|
||||
has_many :recorded_videos, :class_name => "JamRuby::RecordedVideo", :foreign_key => :recording_id, :dependent => :destroy
|
||||
has_many :recorded_backing_tracks, :class_name => "JamRuby::RecordedBackingTrack", :foreign_key => :recording_id, :dependent => :destroy
|
||||
has_many :recorded_jam_track_tracks, :class_name => "JamRuby::RecordedJamTrackTrack", :foreign_key => :recording_id, :dependent => :destroy
|
||||
has_many :comments, :class_name => "JamRuby::RecordingComment", :foreign_key => "recording_id", :dependent => :destroy
|
||||
has_many :likes, :class_name => "JamRuby::RecordingLiker", :foreign_key => "recording_id", :dependent => :destroy
|
||||
has_many :plays, :class_name => "JamRuby::PlayablePlay", :as => :playable, :dependent => :destroy
|
||||
|
|
@ -20,6 +21,8 @@ module JamRuby
|
|||
belongs_to :owner, :class_name => "JamRuby::User", :inverse_of => :owned_recordings, :foreign_key => 'owner_id'
|
||||
belongs_to :band, :class_name => "JamRuby::Band", :inverse_of => :recordings
|
||||
belongs_to :music_session, :class_name => "JamRuby::ActiveMusicSession", :inverse_of => :recordings, foreign_key: :music_session_id
|
||||
belongs_to :jam_track, :class_name => "JamRuby::JamTrack", :inverse_of => :recordings, :foreign_key => 'jam_track_id'
|
||||
belongs_to :jam_track_initiator, :class_name => "JamRuby::User", :inverse_of => :initiated_jam_track_recordings, :foreign_key => 'jam_track_initiator_id'
|
||||
|
||||
accepts_nested_attributes_for :recorded_tracks, :mixes, :claimed_recordings, allow_destroy: true
|
||||
|
||||
|
|
@ -223,6 +226,14 @@ module JamRuby
|
|||
recording.recorded_backing_tracks << RecordedBackingTrack.create_from_backing_track(backing_track, recording)
|
||||
end
|
||||
end
|
||||
|
||||
if music_session.jam_track
|
||||
music_session.jam_track.jam_track_tracks.each do |jam_track_track|
|
||||
recording.recorded_jam_track_tracks << RecordedJamTrackTrack.create_from_jam_track_track(jam_track_track, recording)
|
||||
end
|
||||
recording.jam_track = music_session.jam_track
|
||||
recording.jam_track_initiator = music_session.jam_track_initiator
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -556,7 +567,7 @@ module JamRuby
|
|||
:recording_id => recorded_item.recording_id,
|
||||
:client_track_id => recorded_item.client_track_id,
|
||||
:next => recorded_item.id
|
||||
})
|
||||
})
|
||||
else
|
||||
|
||||
end
|
||||
|
|
@ -678,6 +689,24 @@ module JamRuby
|
|||
self.save(:validate => false)
|
||||
end
|
||||
|
||||
def add_timeline(timeline)
|
||||
tracks = timeline["tracks"]
|
||||
|
||||
raise JamArgumentError, "tracks must be specified" unless tracks
|
||||
|
||||
jam_tracks = tracks.select {|track| track["type"] == "jam_track"}
|
||||
jam_tracks.each do |client_jam_track|
|
||||
recorded_jam_track_track = RecordedJamTrackTrack.find_by_jam_track_track_id(client_jam_track["id"])
|
||||
if recorded_jam_track_track
|
||||
recorded_jam_track_track.timeline = client_jam_track["timeline"].to_json
|
||||
recorded_jam_track_track.save!
|
||||
else
|
||||
@@log.error("unable to find JamTrackTrack with id #{recorded_jam_track_track.id}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
def self.validate_user_is_band_member(user, band)
|
||||
unless band.users.exists? user
|
||||
|
|
|
|||
|
|
@ -124,6 +124,10 @@ module JamRuby
|
|||
has_many :recorded_videos, :foreign_key => "user_id", :class_name => "JamRuby::RecordedVideo", :inverse_of => :user
|
||||
has_many :recorded_backing_tracks, :foreign_key => "user_id", :class_name => "JamRuby::RecordedBackingTrack", :inverse_of => :user
|
||||
has_many :quick_mixes, :foreign_key => "user_id", :class_name => "JamRuby::QuickMix", :inverse_of => :user
|
||||
has_many :recorded_jam_track_tracks, :foreign_key => "user_id", :class_name => "JamRuby::RecordedJamTrackTrack", :inverse_of => :user
|
||||
|
||||
# jam track recordings started
|
||||
has_many :initiated_jam_track_recordings, :foreign_key => 'jam_track_initiator_id', :class_name => "JamRuby::Recording", :inverse_of => :jam_track_initiator
|
||||
|
||||
# invited users
|
||||
has_many :invited_users, :foreign_key => "sender_id", :class_name => "JamRuby::InvitedUser"
|
||||
|
|
|
|||
|
|
@ -111,6 +111,7 @@ module JamRuby
|
|||
end
|
||||
|
||||
def place_order(current_user, jam_track)
|
||||
jam_track_right = nil
|
||||
account = get_account(current_user)
|
||||
if (account.present?)
|
||||
begin
|
||||
|
|
@ -136,7 +137,7 @@ module JamRuby
|
|||
else
|
||||
raise RecurlyClientError, "Could not find account to place order."
|
||||
end
|
||||
account
|
||||
jam_track_right
|
||||
end
|
||||
|
||||
def find_or_create_account(current_user, billing_info=nil)
|
||||
|
|
|
|||
|
|
@ -268,7 +268,6 @@ FactoryGirl.define do
|
|||
association :recording, factory: :recording
|
||||
end
|
||||
|
||||
|
||||
factory :recorded_video, :class => JamRuby::RecordedVideo do
|
||||
sequence(:client_video_source_id) { |n| "client_video_source_id-#{n}"}
|
||||
fully_uploaded true
|
||||
|
|
@ -277,6 +276,12 @@ FactoryGirl.define do
|
|||
association :recording, factory: :recording
|
||||
end
|
||||
|
||||
factory :recorded_jam_track_track, :class => JamRuby::RecordedJamTrackTrack do
|
||||
association :user, factory: :user
|
||||
association :recording, factory: :recording
|
||||
association :jam_track_track, factory: :jam_track_track
|
||||
end
|
||||
|
||||
factory :instrument, :class => JamRuby::Instrument do
|
||||
description { |n| "Instrument #{n}" }
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1073,6 +1073,33 @@ describe Recording do
|
|||
RecordedVideo.find_by_id(video.id).should_not be_nil
|
||||
end
|
||||
end
|
||||
|
||||
describe "add_timeline" do
|
||||
|
||||
let!(:recorded_jam_track_track) {FactoryGirl.create(:recorded_jam_track_track)}
|
||||
let(:recording) {recorded_jam_track_track.recording}
|
||||
let(:timeline_data) {{"sample" => "data"}}
|
||||
let(:good_timeline) { {
|
||||
"tracks" => [
|
||||
{
|
||||
"id" => recorded_jam_track_track.jam_track_track.id,
|
||||
"timeline" => timeline_data,
|
||||
"type" => "jam_track"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
it "applies timeline data correctly" do
|
||||
recording.add_timeline good_timeline
|
||||
recorded_jam_track_track.reload
|
||||
JSON.parse(recorded_jam_track_track.timeline).should eq(timeline_data)
|
||||
end
|
||||
|
||||
it "fails if no tracks data" do
|
||||
expect { recording.add_timeline({}) }.to raise_error(JamRuby::JamArgumentError)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -529,10 +529,12 @@
|
|||
|
||||
if(server.connecting) {
|
||||
logger.error("server.connect should never be called if we are already connecting. cancelling.")
|
||||
// XXX should return connectDeferred, but needs to be tested/vetted
|
||||
return;
|
||||
}
|
||||
if(server.connected) {
|
||||
logger.error("server.connect should never be called if we are already connected. cancelling.")
|
||||
// XXX should return connectDeferred, but needs to be tested/vetted
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -678,7 +680,12 @@
|
|||
logger.info("server.send(" + jsMessage + ")");
|
||||
}
|
||||
if (server !== undefined && server.socket !== undefined && server.socket.send !== undefined) {
|
||||
server.socket.send(jsMessage);
|
||||
try {
|
||||
server.socket.send(jsMessage);
|
||||
}
|
||||
catch(err) {
|
||||
logger.warn("error when sending on websocket: " + err)
|
||||
}
|
||||
} else {
|
||||
logger.warn("Dropped message because server connection is closed.");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
}
|
||||
|
||||
function beforeShow() {
|
||||
$dialog.data('result', null)
|
||||
emptyList();
|
||||
resetPagination();
|
||||
showing = true;
|
||||
|
|
@ -77,18 +78,8 @@
|
|||
// tell the server we are about to start a recording
|
||||
rest.openJamTrack({id: context.JK.CurrentSessionModel.id(), jam_track_id: jamTrack.id})
|
||||
.done(function(response) {
|
||||
context.jamClient.JamTrackStopPlay();
|
||||
var result = context.jamClient.JamTrackPlay(jamTrack.id);
|
||||
|
||||
logger.debug("JamTrackPlay response: %o", result);
|
||||
|
||||
if(result) {
|
||||
app.layout.closeDialog('open-jam-track-dialog');
|
||||
}
|
||||
else {
|
||||
logger.error("unable to open jam track")
|
||||
}
|
||||
|
||||
$dialog.data('result', {success:true, jamTrack: jamTrack})
|
||||
app.layout.closeDialog('open-jam-track-dialog');
|
||||
})
|
||||
.fail(function(jqXHR) {
|
||||
app.notifyServerError(jqXHR, "Unable to Open JamTrack For Playback");
|
||||
|
|
|
|||
|
|
@ -2,10 +2,471 @@ $ = jQuery
|
|||
context = window
|
||||
context.JK ||= {};
|
||||
|
||||
context.JK.DownloadJamTrack = class SyncViewer
|
||||
constructor: (@app) ->
|
||||
# This is the sequence of how this widget works:
|
||||
# checkState() is the heart of the state machine; it is called to get things going, and is called whenevr a state ends
|
||||
# checkState() checks first against what the client thinks about the state of the JamTrack;
|
||||
# if it on the disk then the state machine may enter one of:
|
||||
# * synchronized
|
||||
# * keying
|
||||
#
|
||||
# if it's still on the server, then the state machine may be:
|
||||
# * packaging
|
||||
# * downloading
|
||||
#
|
||||
# errored state can be entered from @jamTrack.jam_track_right_id
|
||||
#
|
||||
# other state; you augment the error to the user by suppling @errorMessage before transitioning
|
||||
#
|
||||
# no-client is the way the widget behaves when you are in a normal browser (i.e., nothing happens other than tell the user to use the client)
|
||||
#
|
||||
# Discussion of the different states:
|
||||
# There are different states that a JamTrack can be in.
|
||||
# The final success state is that the JamTrack is on disk and loadable. (show synchronized state)
|
||||
# But there are others until you get there:
|
||||
# The JamTrack does not exist on the server, so we will create it (packaging state)
|
||||
# The JamTrack exists on the server, but not on disk, so we will download it (downloading state)
|
||||
# The JamTrack is on the disk, but does not yet have keys, so we will fetch them (keying)
|
||||
|
||||
context.JK.DownloadJamTracks = {}
|
||||
context.JK.DownloadJamTrack = class DownloadJamTrack
|
||||
constructor: (@app, jamTrack, size = 'large') ->
|
||||
@EVENTS = context.JK.EVENTS
|
||||
@rest = context.JK.Rest()
|
||||
@logger = context.JK.logger
|
||||
@jamTrack = jamTrack
|
||||
@size = size
|
||||
@attemptedEnqueue = false
|
||||
@errorReason = null
|
||||
@errorMessage = null
|
||||
@transitionTimer = null
|
||||
@downloadTimer = null
|
||||
@trackDetail = null
|
||||
@stateHolder = null
|
||||
@active = false
|
||||
@startTime = null
|
||||
@attempts = 0
|
||||
@tracked = false
|
||||
@ajaxEnqueueAborted = false
|
||||
@ajaxGetJamTrackRightAborted = false
|
||||
|
||||
throw "no JamTrack specified" unless @jamTrack?
|
||||
throw "invalid size" if @size != 'large' && @size != 'small'
|
||||
throw "no JamTrack version" unless @jamTrack.version?
|
||||
|
||||
@path = []
|
||||
@states = {
|
||||
no_client: { name: 'no-client', show: @showNoClient, leaf: true },
|
||||
synchronized: { name: 'synchronized', show: @showSynchronized, leaf: true},
|
||||
packaging: { name: 'packaging', show: @showPackaging },
|
||||
downloading: { name: 'downloading', show: @showDownloading },
|
||||
keying: { name: 'keying', show: @showKeying, max_time: 10000 },
|
||||
initial: { name: 'initial', show: @showInitial },
|
||||
quiet: { name: 'quiet', show: @showQuiet },
|
||||
errored: { name: 'errored', show: @showError, leaf: true}
|
||||
}
|
||||
|
||||
context.JK.DownloadJamTracks[@jamTrack.id] = this
|
||||
downloadJamTrackTemplate = $('#template-download-jamtrack')
|
||||
throw "no download jamtrack template" if not downloadJamTrackTemplate.exists()
|
||||
|
||||
@root = $(downloadJamTrackTemplate.html())
|
||||
@stateHolder = @root.find('.state')
|
||||
@root.on('remove', this.destroy) # automatically destroy self when removed from DOM
|
||||
|
||||
# populate in template and visual transition functions
|
||||
for state, data of @states
|
||||
data.template = $("#template-download-jamtrack-state-#{data.name}")
|
||||
|
||||
# start off in quiet state, but don't do it through transition system. The transition system expects a change, not initial state
|
||||
@state = @states.quiet
|
||||
|
||||
this.showState()
|
||||
|
||||
|
||||
# after you've created the DownloadJamTrack widget, call synchronize which will begin ensuring that the jamtrack
|
||||
# is downloaded and ready to open
|
||||
init: () =>
|
||||
@root = $($('#template-download-jamtrack').html())
|
||||
@active = true
|
||||
@root.addClass('active')
|
||||
this.reset()
|
||||
|
||||
# check if we are in a browser or client
|
||||
if !gon.isNativeClient
|
||||
this.transition(@states.no_client)
|
||||
else
|
||||
this.transition(@states.initial)
|
||||
|
||||
# when done with the widget, call destroy; this ensures it's not still active, and tracks final metrics
|
||||
destroy: () =>
|
||||
$(this).off()
|
||||
@active = false
|
||||
@root.removeClass('active')
|
||||
this.trackProgress()
|
||||
# since we are not in a leave node, we need to report a state since this is effectively our end state
|
||||
this.reset()
|
||||
|
||||
reset: () =>
|
||||
@path = []
|
||||
@attempts = 0
|
||||
@tracked = false
|
||||
@startTime = new Date()
|
||||
# reset attemptedEnqueue to false, to allow one attempt to enqueue
|
||||
@attemptedEnqueue = false
|
||||
this.clearDownloadTimer()
|
||||
this.clearTransitionTimer()
|
||||
this.abortEnqueue()
|
||||
this.abortGetJamTrackRight()
|
||||
for state, data of @states
|
||||
if data.timer?
|
||||
clearInterval(data.timer)
|
||||
data.timer = null
|
||||
|
||||
abortEnqueue: () =>
|
||||
if @ajaxEnqueueAborted
|
||||
@logger.debug("DownloadJamTrack: aborting ajax enqueue")
|
||||
# we need to clear out @ajaxEnqueue *before* calling abort(), because the .fail callback fires inline
|
||||
ajax = @ajaxEnqueueAborted
|
||||
@ajaxEnqueueAborted = true
|
||||
ajax.abort()
|
||||
|
||||
abortGetJamTrackRight: () =>
|
||||
if @ajaxGetJamTrackRightAborted
|
||||
@logger.debug("DownloadJamTrack: aborting ajax GetJamTrackRight")
|
||||
# we need to clear out @ajaxEnqueue *before* calling abort(), because the .fail callback fires inline
|
||||
ajax = @ajaxGetJamTrackRightAborted
|
||||
@ajaxGetJamTrackRightAborted = true
|
||||
ajax.abort()
|
||||
|
||||
showState: () =>
|
||||
@state.stateStartTime = new Date();
|
||||
@stateHolder.children().remove()
|
||||
@stateHolder.append(context._.template(@state.template.html(), @jamTrack, { variable: 'data' }))
|
||||
@stateHolder.find('.' + @size).removeClass('hidden')
|
||||
@state.show()
|
||||
|
||||
# report a stat now that we've reached the end of this widget's journey
|
||||
trackProgress: () =>
|
||||
|
||||
# do not double-report
|
||||
if @tracked
|
||||
return
|
||||
|
||||
if @path.length == 0
|
||||
return
|
||||
|
||||
unless @state.leaf
|
||||
# we've been asked to report at a non-leaf node, meaning the user must have cancelled
|
||||
@path.push('user-cancelled')
|
||||
|
||||
flattened_path = @path.join('-')
|
||||
|
||||
data = {
|
||||
value: 1,
|
||||
path: flattened_path,
|
||||
duration: (new Date().getTime() - @startTime.getTime()) / 1000,
|
||||
attempts: @attempts,
|
||||
user_id: context.JK.currentUserId,
|
||||
user_name: context.JK.currentUserName}
|
||||
if @state == @states.errored
|
||||
data.result = 'error'
|
||||
data.detail = @errorReason
|
||||
else
|
||||
data.result = 'success'
|
||||
|
||||
context.stats.write('web.jamtrack.downloader', data)
|
||||
@tracked = true
|
||||
|
||||
showPackaging: () =>
|
||||
@logger.debug("showing #{@state.name}")
|
||||
this.expectTransition()
|
||||
|
||||
showDownloading: () =>
|
||||
@logger.debug("showing #{@state.name}")
|
||||
# while downloading, we don't run the transition timer, because the download API is guaranteed to call success, or failure, eventually
|
||||
context.jamClient.JamTrackDownload(@jamTrack.id, this.makeDownloadSuccessCallback(), this.makeDownloadFailureCallback())
|
||||
|
||||
showKeying: () =>
|
||||
@logger.debug("showing #{@state.name}")
|
||||
context.jamClient.JamTrackKeysRequest()
|
||||
this.waitForState()
|
||||
|
||||
showQuiet: () =>
|
||||
@logger.debug("showing #{@state.name}")
|
||||
|
||||
showInitial: () =>
|
||||
@logger.debug("showing #{@state.name}")
|
||||
@attempts = @attempts + 1
|
||||
this.expectTransition()
|
||||
context.JK.SubscriptionUtils.subscribe('jam_track_right', @jamTrack.jam_track_right_id).on(context.JK.EVENTS.SUBSCRIBE_NOTIFICATION, this.onJamTrackRightEvent)
|
||||
this.checkState()
|
||||
|
||||
showError: () =>
|
||||
@logger.debug("showing #{@state.name}")
|
||||
context.JK.SubscriptionUtils.unsubscribe('jam_track_right', @jamTrack.jam_track_right_id)
|
||||
|
||||
if @size == 'large'
|
||||
@stateHolder.find('.msg').text(@errorMessage)
|
||||
@stateHolder.find('.retry-button').click(this.retry)
|
||||
else
|
||||
@stateHolder.find('.msg').text(@jamTrack.name + ' (error)')
|
||||
@stateHolder.find('.errormsg').text(@errorMessage)
|
||||
@stateHolder.find('.retry-button').on('click', this.retry)
|
||||
|
||||
retryMsg = ''
|
||||
if @attempts > 1
|
||||
retryMsg = 'Continue retrying or contact support@jamkazam.com'
|
||||
|
||||
@stateHolder.find('.retry').text(retryMsg)
|
||||
|
||||
showSynchronized: () =>
|
||||
@logger.debug("showing #{@state.name}")
|
||||
context.JK.SubscriptionUtils.unsubscribe('jam_track_right', @jamTrack.jam_track_right_id)
|
||||
|
||||
showNoClient: () =>
|
||||
@logger.debug("showing #{@state.name}")
|
||||
|
||||
downloadCheck: () =>
|
||||
@logger.debug "downloadCheck"
|
||||
|
||||
retry: () =>
|
||||
@path = []
|
||||
@path.push('retry')
|
||||
# just switch to the initial state again, causing the loop to start again
|
||||
this.transition(@states.initial)
|
||||
return false
|
||||
|
||||
clearStateTimer: () =>
|
||||
if @state.timer?
|
||||
clearInterval(@state.timer)
|
||||
@state.timer = null
|
||||
|
||||
stateIntervalCheck: () =>
|
||||
this.checkState()
|
||||
|
||||
# if the timer is null now, then it must have been whacked due to a state change
|
||||
# if not, then let's see if we have timed out
|
||||
if @state.timer?
|
||||
if (new Date()).getTime() - @state.stateStartTime.getTime() > @state.max_time
|
||||
@logger.debug("The current step (#{@state.name}) took too long")
|
||||
|
||||
if @state == @states.keying
|
||||
# specific message
|
||||
this.transitionError("#{@state.name}-timeout", "It took too long for the JamTrack to be keyed.")
|
||||
else
|
||||
# generic message
|
||||
this.transitionError("#{@state.name}-timeout", "The current step (#{@state.name}) took too long")
|
||||
|
||||
|
||||
# sets an interval timer for every second, waiting for the status to change
|
||||
waitForState: () =>
|
||||
unless @active
|
||||
@logger.error("DownloadJamTrack: ignoring waitForState because we are not active")
|
||||
|
||||
@state.timer = setInterval(this.stateIntervalCheck, 1000)
|
||||
|
||||
|
||||
# unused atm; the backend is good about always signalling. we still should though
|
||||
expectDownload: () =>
|
||||
unless @active
|
||||
@logger.error("DownloadJamTrack: ignoring expectDownload because we are not active")
|
||||
|
||||
# every 10 seconds, wake up and check the server and see if we missed a state transition
|
||||
this.clearDownloadTimer()
|
||||
@downloadTimer = setTimeout(this.downloadCheck, 10000)
|
||||
|
||||
clearDownloadTimer: () =>
|
||||
if @downloadTimer?
|
||||
clearTimeout(@downloadTimer)
|
||||
@downloadTimer = null
|
||||
|
||||
transitionError: (reasonCode, errorMessage) =>
|
||||
@errorReason = reasonCode
|
||||
@errorMessage = errorMessage
|
||||
this.transition(@states.errored)
|
||||
|
||||
transitionCheck: () =>
|
||||
this.checkState()
|
||||
|
||||
# this should be called every time something changes statefully, to restart a 12 second timer to hit the server for update.
|
||||
# if everything is moving snappily, we won't have to query the server much, because we are also getting subscription events
|
||||
# about any changes to the status of the jam track. But, we could miss a message or there could be a path in the server where
|
||||
# we don't get an event, so that's why, after 12 seconds, we'll still go to the server and check.
|
||||
# exception: this should not be runngi
|
||||
expectTransition: () =>
|
||||
unless @active
|
||||
@logger.error("DownloadJamTrack: ignoring expectTransition because we are not active")
|
||||
|
||||
# every 12 seconds, wake up and check the server and see if we missed a state transition
|
||||
this.clearTransitionTimer()
|
||||
@transitionTimer = setTimeout(this.transitionCheck, 12000)
|
||||
|
||||
clearTransitionTimer: () =>
|
||||
if @transitionTimer?
|
||||
clearTimeout(@transitionTimer)
|
||||
@transitionTimer = null
|
||||
|
||||
transition: (newState) =>
|
||||
unless @active
|
||||
@logger.error("DownloadJamTrack: ignoring state change because we are not active")
|
||||
return
|
||||
|
||||
if newState == @state
|
||||
@logger.debug("DownloadJamTrack: ignoring state change #{@state.name} #{newState}")
|
||||
return
|
||||
|
||||
if @state?
|
||||
@logger.debug("DownloadJamTrack: state change: #{@state.name} => #{newState.name}")
|
||||
# make sure there is no timer running on the old state
|
||||
this.clearTransitionTimer()
|
||||
this.clearStateTimer()
|
||||
this.abortEnqueue()
|
||||
@logger.debug("aborting getJamTrack right on state change")
|
||||
this.abortGetJamTrackRight()
|
||||
else
|
||||
@logger.debug("DownloadJamTrack: initial state: #{newState.name}")
|
||||
|
||||
@state = newState
|
||||
|
||||
# track which states were taken
|
||||
@path.push(@state.name)
|
||||
|
||||
if @state.leaf
|
||||
this.trackProgress()
|
||||
|
||||
this.showState()
|
||||
|
||||
$(this).triggerHandler(@EVENTS.JAMTRACK_DOWNLOADER_STATE_CHANGED, {state: @state})
|
||||
|
||||
checkState: () =>
|
||||
# check for the success state against the local state of the client... if it's playable, then we should be OK
|
||||
@trackDetail = context.jamClient.JamTrackGetTrackDetail (@jamTrack.id)
|
||||
|
||||
@logger.debug("DownloadJamTrack: JamTrackGetTrackDetail.key_state: " + @trackDetail.key_state)
|
||||
|
||||
# first check if the version is not the same; if so, invalidate.
|
||||
|
||||
if @trackDetail.version?
|
||||
if @jamTrack.version != @trackDetail.version
|
||||
@logger.info("DownloadJamTrack: JamTrack on disk is different version (stored: #{@trackDetail.version}, server: #{@jamTrack.version}. Invalidating")
|
||||
context.jamClient.InvalidateJamTrack(@jamTrack.id)
|
||||
@trackDetail = context.jamClient.JamTrackGetTrackDetail (@jamTrack.id)
|
||||
|
||||
if @trackDetail.version?
|
||||
@logger.error("after invalidating package, the version is still wrong!")
|
||||
throw "after invalidating package, the version is still wrong!"
|
||||
|
||||
switch @trackDetail.key_state
|
||||
when 'pending'
|
||||
this.transition(@states.keying)
|
||||
when 'not authorized'
|
||||
# TODO: if not authorized, do we need to re-initiate a keying attempt?
|
||||
this.transition(@states.keying)
|
||||
when 'ready'
|
||||
this.transition(@states.synchronized)
|
||||
when 'unknown'
|
||||
@ajaxGetJamTrackRightAborted = false
|
||||
@rest.getJamTrackRight({id: @jamTrack.id})
|
||||
.done(this.processJamTrackRight)
|
||||
.fail(this.processJamTrackRightFail)
|
||||
|
||||
|
||||
processSigningState: (signingState) =>
|
||||
@logger.debug("DownloadJamTrack: processSigningState: " + signingState)
|
||||
|
||||
switch signingState
|
||||
when 'QUIET'
|
||||
if @attemptedEnqueue
|
||||
# this means we've already tried to poke the server. something is wrong
|
||||
this.transitionError("enqueue-timeout", "The server has not begun building your JamTrack.")
|
||||
else
|
||||
this.expectTransition()
|
||||
|
||||
this.attemptToEnqueue()
|
||||
when 'QUEUED'
|
||||
# when it's queued, there is nothing to do except wait.
|
||||
this.transition(@states.packaging)
|
||||
when 'QUEUED_TIMEOUT'
|
||||
this.transitionError("queued-timeout", "The server took too long to begin processing your JamTrack.")
|
||||
when 'SIGNING'
|
||||
this.transition(@states.packaging)
|
||||
when 'SIGNING_TIMEOUT'
|
||||
this.transitionError("signing-timeout", "The server took too long to create your JamTrack.")
|
||||
when 'SIGNED'
|
||||
this.transition(@states.downloading)
|
||||
when 'ERROR'
|
||||
if @attemptedEnqueue
|
||||
# this means we've already tried to poke the server. something is wrong
|
||||
this.transitionError("package-error", "The server failed to create your package.")
|
||||
else
|
||||
this.expectTransition()
|
||||
|
||||
this.attemptToEnqueue()
|
||||
else
|
||||
@logger.error("unknown state: " + signingState)
|
||||
this.transitionError("unknown-state-#{signingState}", "The server sent an unknown state message: " + signingState)
|
||||
|
||||
attemptToEnqueue: () =>
|
||||
@attemptedEnqueue = true
|
||||
@ajaxEnqueueAborted = false
|
||||
@rest.enqueueJamTrack({id: @jamTrack.id})
|
||||
.done(this.processEnqueueJamTrack)
|
||||
.fail(this.processEnqueueJamTrackFail)
|
||||
|
||||
|
||||
processJamTrackRight: (myJamTrack) =>
|
||||
unless @ajaxGetJamTrackRightAborted
|
||||
this.processSigningState(myJamTrack.signing_state)
|
||||
else
|
||||
@logger.debug("DownloadJamTrack: ignoring processJamTrackRight response")
|
||||
|
||||
processJamTrackRightFail: () =>
|
||||
unless @ajaxGetJamTrackRightAborted?
|
||||
this.transitionError("status-check-error", "Unable to check with the server on the status of your JamTrack.")
|
||||
else
|
||||
@logger.debug("DownloadJamTrack: ignoring processJamTrackRightFail response")
|
||||
|
||||
processEnqueueJamTrack: (enqueueResponse) =>
|
||||
unless @ajaxEnqueueAborted
|
||||
this.expectTransition() # the act of enqueuing should send down events to the client. we wait...
|
||||
else
|
||||
@logger.debug("DownloadJamTrack: ignoring processEnqueueJamTrack response")
|
||||
|
||||
processEnqueueJamTrackFail: () =>
|
||||
unless @ajaxEnqueueAborted
|
||||
this.transitionError("enqueue-error", "Unable to ask the server to build your JamTrack.")
|
||||
else
|
||||
@logger.debug("DownloadJamTrack: ignoring processEnqueueJamTrackFail response")
|
||||
|
||||
onJamTrackRightEvent: (e, data) =>
|
||||
@logger.debug("DownloadJamTrack: subscription notification received: type:" + data.type)
|
||||
this.expectTransition()
|
||||
this.processSigningState(data.body.signing_state)
|
||||
|
||||
downloadProgressCallback: (bytesReceived, bytesTotal, downloadSpeedMegSec, timeRemaining) =>
|
||||
bytesReceived = Number(bytesReceived)
|
||||
bytesTotal = Number(bytesTotal)
|
||||
# bytesTotal from Qt is not trust worthy; trust server's answer instead
|
||||
#progressWidth = ((bytesReceived / updateSize) * 100).toString() + "%";
|
||||
# $('#progress-bar').width(progressWidth)
|
||||
|
||||
downloadSuccessCallback: (updateLocation) =>
|
||||
# is the package loadable yet?
|
||||
@logger.debug("DownloadJamTrack: download complete - on to keying")
|
||||
this.transition(@states.keying)
|
||||
|
||||
downloadFailureCallback: (errorMsg) =>
|
||||
|
||||
this.transitionError("download-error", errorMsg)
|
||||
|
||||
# makes a function name for the backend
|
||||
makeDownloadProgressCallback: () =>
|
||||
"JK.DownloadJamTracks['#{@jamTrack.id}'].downloadProgressCallback"
|
||||
|
||||
# makes a function name for the backend
|
||||
makeDownloadSuccessCallback: () =>
|
||||
"JK.DownloadJamTracks['#{@jamTrack.id}'].downloadSuccessCallback"
|
||||
|
||||
# makes a function name for the backend
|
||||
makeDownloadFailureCallback: () =>
|
||||
"JK.DownloadJamTracks['#{@jamTrack.id}'].downloadFailureCallback"
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,8 @@
|
|||
e.stopPropagation();
|
||||
|
||||
var $fader = $(this);
|
||||
|
||||
var sessionModel = window.JK.CurrentSessionModel || null;
|
||||
|
||||
var mediaControlsDisabled = $fader.data('media-controls-disabled');
|
||||
if(mediaControlsDisabled) {
|
||||
var mediaTrackOpener = $fader.data('media-track-opener');
|
||||
|
|
@ -28,11 +29,16 @@
|
|||
return false;
|
||||
}
|
||||
|
||||
if(sessionModel && sessionModel.areControlsLockedForJamTrackRecording() && $control.closest('.session-track').data('track_data').type == 'jam_track') {
|
||||
window.JK.prodBubble($fader, 'jamtrack-controls-disabled', {}, {positions:['top'], offsetParent: $fader.closest('.screen')})
|
||||
return false;
|
||||
}
|
||||
|
||||
if($fader.data('showHelpAboutMediaMixers')) {
|
||||
if(window.JK.CurrentSessionModel) {
|
||||
if(!window.JK.CurrentSessionModel.hasShownAudioMediaMixerHelp()) {
|
||||
if(sessionModel) {
|
||||
if(!sessionModel.hasShownAudioMediaMixerHelp()) {
|
||||
window.JK.prodBubble($fader, 'volume-media-mixers', {}, {positions:['top'], offsetParent: $fader.closest('.screen')})
|
||||
window.JK.CurrentSessionModel.markShownAudioMediaMixerHelp()
|
||||
sessionModel.markShownAudioMediaMixerHelp()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -138,10 +144,16 @@
|
|||
|
||||
var mediaControlsDisabled = $draggingFaderHandle.data('media-controls-disabled');
|
||||
var mediaTrackOpener = $draggingFaderHandle.data('media-track-opener');
|
||||
|
||||
var sessionModel = window.JK.CurrentSessionModel || null;
|
||||
|
||||
if(mediaControlsDisabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(sessionModel && sessionModel.areControlsLockedForJamTrackRecording() && $draggingFaderHandle.closest('.session-track').data('track_data').type == 'jam_track') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -707,6 +707,16 @@
|
|||
|
||||
function TrackSetInstrument(track, instrumentId) {}
|
||||
|
||||
function JamTrackStopPlay() {}
|
||||
function JamTrackPlay(){return true; }
|
||||
function JamTrackIsPlayable() {
|
||||
return true;
|
||||
}
|
||||
function JamTrackGetTrackDetail() {
|
||||
return {key_state: 'unknown'}
|
||||
}
|
||||
function JamTrackKeysRequest() {}
|
||||
function JamTrackDownload() {}
|
||||
// Method which sets volume
|
||||
function UpdateMixer(mixerId) {}
|
||||
|
||||
|
|
@ -1062,6 +1072,13 @@
|
|||
this.TrackGetChatUsesMusic = TrackGetChatUsesMusic;
|
||||
this.TrackSetChatUsesMusic = TrackSetChatUsesMusic;
|
||||
|
||||
this.JamTrackStopPlay = JamTrackStopPlay;
|
||||
this.JamTrackPlay = JamTrackPlay;
|
||||
this.JamTrackIsPlayable = JamTrackIsPlayable;
|
||||
this.JamTrackGetTrackDetail = JamTrackGetTrackDetail;
|
||||
this.JamTrackKeysRequest = JamTrackKeysRequest;
|
||||
this.JamTrackDownload = JamTrackDownload;
|
||||
|
||||
// Scoring Knobs
|
||||
this.GetScoreWorkTimingInterval = GetScoreWorkTimingInterval;
|
||||
this.SetScoreWorkTimingInterval = SetScoreWorkTimingInterval;
|
||||
|
|
|
|||
|
|
@ -45,7 +45,8 @@
|
|||
SUBSCRIBE_NOTIFICATION: 'subscribe_notification',
|
||||
CONNECTION_UP: 'connection_up',
|
||||
CONNECTION_DOWN: 'connection_down',
|
||||
SCREEN_CHANGED: 'screen_changed'
|
||||
SCREEN_CHANGED: 'screen_changed',
|
||||
JAMTRACK_DOWNLOADER_STATE_CHANGED: 'jamtrack_downloader_state'
|
||||
};
|
||||
|
||||
context.JK.ALERT_NAMES = {
|
||||
|
|
|
|||
|
|
@ -1434,6 +1434,28 @@
|
|||
});
|
||||
}
|
||||
|
||||
function getJamTrackRight(options) {
|
||||
var jamTrackId = options['id'];
|
||||
|
||||
return $.ajax({
|
||||
type: "GET",
|
||||
url: '/api/jamtracks/rights/' + jamTrackId + '?' + $.param(options),
|
||||
dataType: "json",
|
||||
contentType: 'application/json'
|
||||
})
|
||||
}
|
||||
|
||||
function enqueueJamTrack(options) {
|
||||
var jamTrackId = options['id'];
|
||||
|
||||
return $.ajax({
|
||||
type: "POST",
|
||||
url: '/api/jamtracks/enqueue?' + jamTrackId + '?' + $.param(options),
|
||||
dataType: "json",
|
||||
contentType: 'applications/json'
|
||||
});
|
||||
}
|
||||
|
||||
function getPurchasedJamTracks(options) {
|
||||
return $.ajax({
|
||||
type: "GET",
|
||||
|
|
@ -1563,13 +1585,23 @@
|
|||
});
|
||||
}
|
||||
|
||||
function validateUrlSite(url, sitetype) {
|
||||
function validateUrlSite(url, sitetype) {
|
||||
return $.ajax({
|
||||
type: "GET",
|
||||
url: '/api/data_validation?sitetype='+sitetype+'&data=' + encodeURIComponent(url),
|
||||
contentType: 'application/json'
|
||||
});
|
||||
}
|
||||
|
||||
function addRecordingTimeline(recordingId, data) {
|
||||
return $.ajax({
|
||||
type: "GET",
|
||||
url: '/api/data_validation?sitetype='+sitetype+'&data=' + encodeURIComponent(url),
|
||||
contentType: 'application/json'
|
||||
type: "POST",
|
||||
url: '/api/recordings/' + recordingId + '/timeline',
|
||||
dataType: "json",
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify(data),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
return self;
|
||||
|
|
@ -1694,6 +1726,8 @@
|
|||
this.updateAudioLatency = updateAudioLatency;
|
||||
this.getJamtracks = getJamtracks;
|
||||
this.getPurchasedJamTracks = getPurchasedJamTracks;
|
||||
this.getJamTrackRight = getJamTrackRight;
|
||||
this.enqueueJamTrack = enqueueJamTrack;
|
||||
this.getBackingTracks = getBackingTracks;
|
||||
this.addJamtrackToShoppingCart = addJamtrackToShoppingCart;
|
||||
this.getShoppingCarts = getShoppingCarts;
|
||||
|
|
@ -1710,6 +1744,7 @@
|
|||
this.createSourceChange = createSourceChange;
|
||||
this.validateUrlSite = validateUrlSite;
|
||||
this.markRecordedBackingTrackSilent = markRecordedBackingTrackSilent;
|
||||
this.addRecordingTimeline = addRecordingTimeline;
|
||||
|
||||
return this;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -4,9 +4,12 @@
|
|||
context.JK = context.JK || {};
|
||||
context.JK.OrderScreen = function(app) {
|
||||
|
||||
var EVENTS = context.JK.EVENTS;
|
||||
var logger = context.JK.logger;
|
||||
|
||||
var $screen = null;
|
||||
var $templateOrderContent = null;
|
||||
var $templatePurchasedJamTrack = null;
|
||||
var $navigation = null;
|
||||
var $billingInfo = null;
|
||||
var $shippingInfo = null;
|
||||
|
|
@ -16,15 +19,23 @@
|
|||
var $paymentInfoPanel = null;
|
||||
var $orderPanel = null;
|
||||
var $thanksPanel = null;
|
||||
var $jamTrackInBrowser = null;
|
||||
var $purchasedJamTrack = null;
|
||||
var $purchasedJamTrackHeader = null;
|
||||
var $purchasedJamTracks = null;
|
||||
var $orderContent = null;
|
||||
var userDetail = null;
|
||||
var step = null;
|
||||
var billing_info = null;
|
||||
var shipping_info = null;
|
||||
var shipping_as_billing = null;
|
||||
var downloadJamTracks = [];
|
||||
var purchasedJamTracks = null;
|
||||
var purchasedJamTrackIterator = 0;
|
||||
|
||||
function beforeShow() {
|
||||
beforeShowPaymentInfo();
|
||||
beforeShowPaymentInfo();
|
||||
resetJamTrackDownloadInfo();
|
||||
}
|
||||
|
||||
function beforeShowPaymentInfo() {
|
||||
|
|
@ -33,6 +44,12 @@
|
|||
renderAccountInfo();
|
||||
}
|
||||
|
||||
function resetJamTrackDownloadInfo() {
|
||||
$purchasedJamTrack.addClass('hidden');
|
||||
$purchasedJamTracks.children().remove()
|
||||
$jamTrackInBrowser.hide('hidden');
|
||||
}
|
||||
|
||||
function renderAccountInfo() {
|
||||
rest.getUserDetail()
|
||||
.done(populateAccountInfo)
|
||||
|
|
@ -81,6 +98,21 @@
|
|||
}
|
||||
|
||||
function afterShow(data) {
|
||||
// XXX : style-test code
|
||||
// moveToThanks({jam_tracks: [{id: 14, jam_track_right_id: 11, name: 'Back in Black'}, {id: 15, jam_track_right_id: 11, name: 'In Bloom'}, {id: 16, jam_track_right_id: 11, name: 'Love Bird Supreme'}]});
|
||||
}
|
||||
|
||||
function beforeHide() {
|
||||
if(downloadJamTracks) {
|
||||
context._.each(downloadJamTracks, function(downloadJamTrack) {
|
||||
downloadJamTrack.destroy();
|
||||
downloadJamTrack.root.remove();
|
||||
})
|
||||
|
||||
downloadJamTracks = [];
|
||||
}
|
||||
purchasedJamTracks = null;
|
||||
purchasedJamTrackIterator = 0;
|
||||
}
|
||||
|
||||
function next(e) {
|
||||
|
|
@ -412,7 +444,7 @@
|
|||
data.shipping_as_billing = shipping_as_billing
|
||||
var orderContentHtml = $(
|
||||
context._.template(
|
||||
$('#template-order-content').html(),
|
||||
$templateOrderContent.html(),
|
||||
data,
|
||||
{variable: 'data'}
|
||||
)
|
||||
|
|
@ -430,13 +462,86 @@
|
|||
beforeShowOrder();
|
||||
}
|
||||
|
||||
function moveToThanks() {
|
||||
function moveToThanks(purchaseResponse) {
|
||||
$("#order_error").addClass("hidden")
|
||||
$paymentInfoPanel.addClass("hidden")
|
||||
$orderPanel.addClass("hidden")
|
||||
$thanksPanel.removeClass("hidden")
|
||||
rest.clearShoppingCart()
|
||||
beforeShowOrder()
|
||||
handleJamTracksPurchased(purchaseResponse.jam_tracks)
|
||||
}
|
||||
|
||||
function handleJamTracksPurchased(jamTracks) {
|
||||
// were any JamTracks purchased?
|
||||
var jamTracksPurchased = jamTracks && jamTracks.length > 0;
|
||||
if(jamTracksPurchased) {
|
||||
if(gon.isNativeClient) {
|
||||
startDownloadJamTracks(jamTracks)
|
||||
}
|
||||
else {
|
||||
$jamTrackInBrowser.removeClass('hidden');
|
||||
}
|
||||
}
|
||||
}
|
||||
function startDownloadJamTracks(jamTracks) {
|
||||
// there can be multiple purchased JamTracks, so we cycle through them
|
||||
|
||||
purchasedJamTracks = jamTracks;
|
||||
|
||||
// populate list of jamtracks purchased, that we will iterate through graphically
|
||||
context._.each(jamTracks, function(jamTrack) {
|
||||
var downloadJamTrack = new context.JK.DownloadJamTrack(app, jamTrack, 'small');
|
||||
var $purchasedJamTrack = $(context._.template(
|
||||
$templatePurchasedJamTrack.html(),
|
||||
jamTrack,
|
||||
{variable: 'data'}
|
||||
));
|
||||
|
||||
$purchasedJamTracks.append($purchasedJamTrack)
|
||||
|
||||
// show it on the page
|
||||
$purchasedJamTrack.append(downloadJamTrack.root)
|
||||
|
||||
downloadJamTracks.push(downloadJamTrack)
|
||||
})
|
||||
|
||||
iteratePurchasedJamTracks();
|
||||
}
|
||||
|
||||
function iteratePurchasedJamTracks() {
|
||||
if(purchasedJamTrackIterator < purchasedJamTracks.length ) {
|
||||
var downloadJamTrack = downloadJamTracks[purchasedJamTrackIterator++];
|
||||
|
||||
// make sure the 'purchasing JamTrack' section can be seen
|
||||
$purchasedJamTrack.removeClass('hidden');
|
||||
|
||||
// the widget indicates when it gets to any transition; we can hide it once it reaches completion
|
||||
$(downloadJamTrack).on(EVENTS.JAMTRACK_DOWNLOADER_STATE_CHANGED, function(e, data) {
|
||||
|
||||
if(data.state == downloadJamTrack.states.synchronized) {
|
||||
logger.debug("jamtrack " + downloadJamTrack.jamTrack.name + " synchronized;")
|
||||
//downloadJamTrack.root.remove();
|
||||
downloadJamTrack.destroy();
|
||||
|
||||
// go to the next JamTrack
|
||||
iteratePurchasedJamTracks()
|
||||
}
|
||||
})
|
||||
|
||||
logger.debug("jamtrack " + downloadJamTrack.jamTrack.name + " downloader initializing")
|
||||
|
||||
// kick off the download JamTrack process
|
||||
downloadJamTrack.init()
|
||||
|
||||
// XXX style-test code
|
||||
// downloadJamTrack.transitionError("package-error", "The server failed to create your package.")
|
||||
|
||||
}
|
||||
else {
|
||||
logger.debug("done iterating over purchased JamTracks")
|
||||
$purchasedJamTrackHeader.text('All purchased JamTracks have been downloaded successfully! You can now play them in a session.')
|
||||
}
|
||||
}
|
||||
|
||||
function moveToPaymentInfo(e) {
|
||||
|
|
@ -506,21 +611,28 @@
|
|||
function initialize() {
|
||||
var screenBindings = {
|
||||
'beforeShow': beforeShow,
|
||||
'afterShow': afterShow
|
||||
'afterShow': afterShow,
|
||||
'beforeHide' : beforeHide
|
||||
};
|
||||
app.bindScreen('order', screenBindings);
|
||||
|
||||
$screen = $("#orderScreen");
|
||||
$paymentInfoPanel = $screen.find(".checkout-payment-info");
|
||||
$orderPanel = $screen.find(".order-panel");
|
||||
$thanksPanel = $screen.find(".thanks-panel");
|
||||
$navigation = $screen.find(".checkout-navigation-bar");
|
||||
$billingInfo = $paymentInfoPanel.find(".billing-address");
|
||||
$shippingInfo = $paymentInfoPanel.find(".shipping-address");
|
||||
$paymentMethod = $paymentInfoPanel.find(".payment-method");
|
||||
$shippingAddress = $paymentInfoPanel.find(".shipping-address-detail");
|
||||
$shippingAsBilling = $paymentInfoPanel.find("#shipping-as-billing");
|
||||
$orderContent = $orderPanel.find(".order-content");
|
||||
$screen = $("#orderScreen");
|
||||
$templateOrderContent = $("#template-order-content");
|
||||
$templatePurchasedJamTrack = $('#template-purchased-jam-track');
|
||||
$paymentInfoPanel = $screen.find(".checkout-payment-info");
|
||||
$orderPanel = $screen.find(".order-panel");
|
||||
$thanksPanel = $screen.find(".thanks-panel");
|
||||
$jamTrackInBrowser = $screen.find(".thanks-detail.jam-tracks-in-browser");
|
||||
$purchasedJamTrack = $thanksPanel.find(".thanks-detail.purchased-jam-track");
|
||||
$purchasedJamTrackHeader = $purchasedJamTrack.find(".purchased-jam-track-header");
|
||||
$purchasedJamTracks = $purchasedJamTrack.find(".purchased-list")
|
||||
$navigation = $screen.find(".checkout-navigation-bar");
|
||||
$billingInfo = $paymentInfoPanel.find(".billing-address");
|
||||
$shippingInfo = $paymentInfoPanel.find(".shipping-address");
|
||||
$paymentMethod = $paymentInfoPanel.find(".payment-method");
|
||||
$shippingAddress = $paymentInfoPanel.find(".shipping-address-detail");
|
||||
$shippingAsBilling = $paymentInfoPanel.find("#shipping-as-billing");
|
||||
$orderContent = $orderPanel.find(".order-content");
|
||||
|
||||
if($screen.length == 0) throw "$screen must be specified";
|
||||
if($navigation.length == 0) throw "$navigation must be specified";
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@
|
|||
var canUpdateBackend = false;
|
||||
var playbackMode = PlaybackMode.EveryWhere;
|
||||
var monitorPlaybackTimeout = null;
|
||||
var jamTrackMode = false; // if true, we use different APIs to determine playback info
|
||||
|
||||
function startPlay() {
|
||||
updateIsPlaying(true);
|
||||
|
|
@ -67,7 +68,7 @@
|
|||
playbackPositionMs = parseInt((offsetLeft / sliderBarWidth) * playbackDurationMs);
|
||||
updateCurrentTimeText(playbackPositionMs);
|
||||
if(canUpdateBackend) {
|
||||
$self.triggerHandler('change-position', {positionMs: playbackPositionMs});
|
||||
$self.triggerHandler('change-position', {positionMs: playbackPositionMs, jamTrackMode: jamTrackMode});
|
||||
canUpdateBackend = false;
|
||||
}
|
||||
}
|
||||
|
|
@ -100,13 +101,25 @@
|
|||
}
|
||||
|
||||
$playButton.on('click', function(e) {
|
||||
startPlay();
|
||||
var sessionModel = context.JK.CurrentSessionModel || null;
|
||||
if(sessionModel && sessionModel.areControlsLockedForJamTrackRecording() && $parentElement.closest('.session-track').data('track_data').type == 'jam_track') {
|
||||
context.JK.prodBubble($fader, 'jamtrack-controls-disabled', {}, {positions:['top'], offsetParent: $playButton})
|
||||
return false;
|
||||
}
|
||||
|
||||
startPlay();
|
||||
return false;
|
||||
});
|
||||
|
||||
$pauseButton.on('click', function(e) {
|
||||
stopPlay();
|
||||
var sessionModel = context.JK.CurrentSessionModel || null;
|
||||
if(sessionModel && sessionModel.areControlsLockedForJamTrackRecording() && $parentElement.closest('.session-track').data('track_data').type == 'jam_track') {
|
||||
context.JK.prodBubble($pauseButton, 'jamtrack-controls-disabled', {}, {positions:['top'], offsetParent: $pauseButton})
|
||||
return false;
|
||||
}
|
||||
|
||||
stopPlay();
|
||||
return false;
|
||||
});
|
||||
|
||||
$sliderBar.on('click', function(e) {
|
||||
|
|
@ -144,16 +157,31 @@
|
|||
});
|
||||
|
||||
function monitorRecordingPlayback() {
|
||||
if(jamTrackMode) {
|
||||
var positionMs = context.jamClient.SessionCurrrentJamTrackPlayPosMs();
|
||||
var duration = context.jamClient.SessionGetJamTracksPlayDurationMs();
|
||||
var durationMs = duration.media_len;
|
||||
var start = duration.start; // needed to understand start offset, and prevent slider from moving in tapins
|
||||
//console.log("JamTrack start: " + start)
|
||||
}
|
||||
else {
|
||||
var positionMs = context.jamClient.SessionCurrrentPlayPosMs();
|
||||
var durationMs = context.jamClient.SessionGetTracksPlayDurationMs();
|
||||
}
|
||||
|
||||
var isPlaying = context.jamClient.isSessionTrackPlaying();
|
||||
var positionMs = context.jamClient.SessionCurrrentPlayPosMs();
|
||||
var durationMs = context.jamClient.SessionGetTracksPlayDurationMs();
|
||||
|
||||
if(positionMs < 0) {
|
||||
// bug in backend?
|
||||
positionMs = 0;
|
||||
}
|
||||
|
||||
update(positionMs, durationMs, isPlaying);
|
||||
|
||||
monitorPlaybackTimeout = setTimeout(monitorRecordingPlayback, 500);
|
||||
}
|
||||
|
||||
function update(currentTimeMs, durationTimeMs, isPlaying) {
|
||||
function update(currentTimeMs, durationTimeMs, isPlaying, offsetStart) {
|
||||
|
||||
if(dragging) {
|
||||
return;
|
||||
|
|
@ -175,6 +203,10 @@
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
if(currentTimeMs < offsetStart) {
|
||||
currentTimeMs = 0; // this is to squelch movement during tap-in period
|
||||
}
|
||||
updateDurationTime(durationTimeMs);
|
||||
updateCurrentTime(currentTimeMs);
|
||||
updateIsPlaying(isPlaying);
|
||||
|
|
@ -247,7 +279,10 @@
|
|||
}
|
||||
}
|
||||
|
||||
function startMonitor() {
|
||||
function startMonitor(_jamTrackMode) {
|
||||
|
||||
jamTrackMode = !!_jamTrackMode;
|
||||
|
||||
monitorRecordingPlayback();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -132,7 +132,6 @@
|
|||
$self.triggerHandler('stoppedRecording', {'recordingId': recording.id, 'reason' : 'rest', 'details' : arguments});
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,6 +82,7 @@
|
|||
var startingRecording = false; // double-click guard
|
||||
var claimedRecording = null;
|
||||
var backing_track_path = null;
|
||||
var jamTrack = null;
|
||||
var playbackControls = null;
|
||||
var promptLeave = false;
|
||||
var rateSessionDialog = null;
|
||||
|
|
@ -93,6 +94,10 @@
|
|||
var $screen = null;
|
||||
var $mixModeDropdown = null;
|
||||
var $templateMixerModeChange = null;
|
||||
var $otherAudioContainer = null;
|
||||
var $myTracksContainer = null;
|
||||
var $liveTracksContainer = null;
|
||||
var downloadJamTrack = null;
|
||||
var $closePlaybackRecording = null;
|
||||
var $openBackingTrack = null;
|
||||
var mediaTrackGroups = [ChannelGroupIds.MediaTrackGroup, ChannelGroupIds.JamTrackGroup, ChannelGroupIds.MetronomeGroup];
|
||||
|
|
@ -106,7 +111,7 @@
|
|||
window.location = '/client#/home';
|
||||
}
|
||||
promptLeave = true;
|
||||
$('#session-mytracks-container').empty();
|
||||
$myTracksContainer.empty();
|
||||
displayDoneRecording(); // assumption is that you can't join a recording session, so this should be safe
|
||||
|
||||
var shareDialog = new JK.ShareDialog(context.JK.app, sessionId, "session");
|
||||
|
|
@ -247,6 +252,7 @@
|
|||
$(sessionModel.recordingModel)
|
||||
.on('startingRecording', function(e, data) {
|
||||
displayStartingRecording();
|
||||
lockControlsforJamTrackRecording();
|
||||
})
|
||||
.on('startedRecording', function(e, data) {
|
||||
if(data.reason) {
|
||||
|
|
@ -292,12 +298,30 @@
|
|||
{
|
||||
displayStartedRecording();
|
||||
displayWhoCreated(data.clientId);
|
||||
lockControlsforJamTrackRecording();
|
||||
}
|
||||
})
|
||||
.on('stoppingRecording', function(e, data) {
|
||||
displayStoppingRecording(data);
|
||||
unlockControlsforJamTrackRecording();
|
||||
})
|
||||
.on('stoppedRecording', function(e, data) {
|
||||
|
||||
unlockControlsforJamTrackRecording();
|
||||
if(sessionModel.selfOpenedJamTracks()) {
|
||||
|
||||
var timeline = context.jamClient.GetJamTrackTimeline();
|
||||
|
||||
rest.addRecordingTimeline(data.recordingId, timeline)
|
||||
.fail(function(){
|
||||
app.notify(
|
||||
{ title: "Unable to Add JamTrack Volume Data",
|
||||
text: "The volume of the JamTrack will not be correct in the recorded mix." },
|
||||
null,
|
||||
true);
|
||||
})
|
||||
}
|
||||
|
||||
if(data.reason) {
|
||||
logger.warn("Recording Discarded: ", data);
|
||||
var reason = data.reason;
|
||||
|
|
@ -461,6 +485,14 @@
|
|||
playbackControls.stopMonitor();
|
||||
}
|
||||
backing_track_path = currentSession == null ? null : currentSession.backing_track_path;
|
||||
|
||||
if(jamTrack == null && (currentSession && currentSession.jam_track != null)) {
|
||||
playbackControls.startMonitor(true);
|
||||
}
|
||||
else if(jamTrack && (currentSession == null || currentSession.jam_track == null)) {
|
||||
playbackControls.stopMonitor();
|
||||
}
|
||||
jamTrack = currentSession == null ? null : currentSession.jam_track;
|
||||
}
|
||||
|
||||
function sessionChanged() {
|
||||
|
|
@ -518,6 +550,14 @@
|
|||
}
|
||||
}
|
||||
|
||||
function resetOtherAudioContent() {
|
||||
if ($('.session-recordings .track').length === 0 && $('.session-recordings .download-jamtrack').length === 0) {
|
||||
$('.session-recordings .when-empty').show();
|
||||
$('.session-recording-name-wrapper').hide();
|
||||
$('.session-recordings .recording-controls').hide();
|
||||
$('.session-recordings .session-recording-name').text('(No audio loaded)')
|
||||
}
|
||||
}
|
||||
function didSelfOpenMedia() {
|
||||
var localMediaMixers = _mixersForGroupIds([ChannelGroupIds.MediaTrackGroup, ChannelGroupIds.JamTrackGroup, ChannelGroupIds.MetronomeGroup], MIX_MODES.MASTER);
|
||||
|
||||
|
|
@ -530,7 +570,7 @@
|
|||
}
|
||||
|
||||
function renderSession() {
|
||||
$('#session-mytracks-container').empty();
|
||||
$myTracksContainer.empty();
|
||||
$('.session-track').remove(); // Remove previous tracks
|
||||
var $voiceChat = $('#voice-chat');
|
||||
$voiceChat.hide();
|
||||
|
|
@ -545,7 +585,9 @@
|
|||
if ($('.session-livetracks .track').length === 0) {
|
||||
$('.session-livetracks .when-empty').show();
|
||||
}
|
||||
|
||||
resetOtherAudioContent();
|
||||
|
||||
/**
|
||||
if ($('.session-recordings .track').length === 0) {
|
||||
$('.session-recordings .when-empty').show();
|
||||
$('.session-recording-name-wrapper').hide();
|
||||
|
|
@ -558,6 +600,7 @@
|
|||
$('.session-recordings .recording-controls').show();
|
||||
checkShowCloseControl();
|
||||
}
|
||||
*/
|
||||
|
||||
// Handle long labels:
|
||||
$(".track-label").dotdotdot()
|
||||
|
|
@ -1047,6 +1090,7 @@
|
|||
|
||||
// Default trackData to participant + no Mixer state.
|
||||
var trackData = {
|
||||
type: 'backing_track',
|
||||
trackId: backingTrack.id,
|
||||
clientId: backingTrack.client_id,
|
||||
name: 'Backing',
|
||||
|
|
@ -1101,19 +1145,14 @@
|
|||
// find the track or tracks that correspond to the mixer
|
||||
var correspondingTracks = []
|
||||
$.each(jamTracks, function(i, jamTrack) {
|
||||
if(mixer.id.indexOf("L") == 0) {
|
||||
if(mixer.id.substring(1) == jamTrack.id) {
|
||||
if(mixer.id == jamTrack.id) {
|
||||
correspondingTracks.push(jamTrack);
|
||||
}
|
||||
else {
|
||||
// this should not be possible
|
||||
alert("Invalid state: the backing track had neither persisted_track_id or persisted_client_id");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if(correspondingTracks.length == 0) {
|
||||
noCorrespondingTracks = true;
|
||||
logger.error("could not correlate jam tracks", jamTrackMixers, jamTracks)
|
||||
app.notify({
|
||||
title: "Unable to Open JamTrack",
|
||||
text: "Could not correlate server and client tracks",
|
||||
|
|
@ -1145,6 +1184,7 @@
|
|||
|
||||
// Default trackData to participant + no Mixer state.
|
||||
var trackData = {
|
||||
type: 'jam_track',
|
||||
trackId: oneOfTheTracks.id,
|
||||
clientId: oneOfTheTracks.client_id,
|
||||
name: name,
|
||||
|
|
@ -1254,6 +1294,7 @@
|
|||
|
||||
// Default trackData to participant + no Mixer state.
|
||||
var trackData = {
|
||||
type: 'metronome',
|
||||
trackId: "MS" + oneOfTheTracks.id,
|
||||
clientId: oneOfTheTracks.client_id,
|
||||
name: "Metronome",
|
||||
|
|
@ -1361,6 +1402,7 @@
|
|||
|
||||
// Default trackData to participant + no Mixer state.
|
||||
var trackData = {
|
||||
type: 'recorded_track',
|
||||
trackId: oneOfTheTracks.id,
|
||||
clientId: oneOfTheTracks.client_id,
|
||||
name: name,
|
||||
|
|
@ -1771,15 +1813,14 @@
|
|||
|
||||
function _addTrack(allowDelete, trackData, mixer, oppositeMixer) {
|
||||
|
||||
var parentSelector = '#session-mytracks-container';
|
||||
var $destination = $(parentSelector);
|
||||
var $destination = $myTracksContainer;
|
||||
if (trackData.clientId !== app.clientId) {
|
||||
parentSelector = '#session-livetracks-container';
|
||||
$destination = $(parentSelector);
|
||||
$destination = $liveTracksContainer
|
||||
$('.session-livetracks .when-empty').hide();
|
||||
}
|
||||
var template = $('#template-session-track').html();
|
||||
var newTrack = $(context.JK.fillTemplate(template, trackData));
|
||||
newTrack.data('track_data', trackData)
|
||||
var audioOverlay = $('.disabled-track-overlay', newTrack);
|
||||
var $trackIconMute = newTrack.find('.track-icon-mute')
|
||||
$trackIconMute.muteSelector().on(EVENTS.MUTE_SELECTED, trackMuteSelected)
|
||||
|
|
@ -1789,7 +1830,7 @@
|
|||
$destination.append(newTrack);
|
||||
|
||||
// Render VU meters and gain fader
|
||||
var trackSelector = parentSelector + ' .session-track[track-id="' + trackData.trackId + '"]';
|
||||
var trackSelector = $destination.selector + ' .session-track[track-id="' + trackData.trackId + '"]';
|
||||
var gainPercent = trackData.gainPercent || 0;
|
||||
connectTrackToMixer(trackSelector, trackData, trackData.mixerId, gainPercent, trackData.group_id);
|
||||
|
||||
|
|
@ -1805,21 +1846,31 @@
|
|||
tracks[trackData.trackId] = new context.JK.SessionTrack(trackData.clientId);
|
||||
}
|
||||
|
||||
|
||||
// something is being shown now in the other audio area
|
||||
function otherAudioFilled() {
|
||||
$('.session-recordings .when-empty').hide();
|
||||
$('.session-recording-name-wrapper').show();
|
||||
}
|
||||
|
||||
function _addRecordingTrack(trackData, mixer, oppositeMixer) {
|
||||
|
||||
otherAudioFilled();
|
||||
|
||||
$('.session-recordings .recording-controls').show();
|
||||
|
||||
var parentSelector = '#session-recordedtracks-container';
|
||||
var $destination = $(parentSelector);
|
||||
|
||||
|
||||
var template = $('#template-session-track').html();
|
||||
var newTrack = $(context.JK.fillTemplate(template, trackData));
|
||||
$destination.append(newTrack);
|
||||
newTrack.data('track_data', trackData);
|
||||
$otherAudioContainer.append(newTrack);
|
||||
if(trackData.preMasteredClass) {
|
||||
context.JK.helpBubble($('.track-instrument', newTrack), 'pre-processed-track', {}, {offsetParent: newTrack.closest('.content-body')});
|
||||
}
|
||||
|
||||
// Render VU meters and gain fader
|
||||
var trackSelector = parentSelector + ' .session-track[track-id="' + trackData.trackId + '"]';
|
||||
var trackSelector = $otherAudioContainer.selector + ' .session-track[track-id="' + trackData.trackId + '"]';
|
||||
var gainPercent = trackData.gainPercent || 0;
|
||||
var $track = connectTrackToMixer(trackSelector, trackData, trackData.mixerId, gainPercent, null);
|
||||
var $trackIconMute = $track.find('.track-icon-mute')
|
||||
|
|
@ -2072,6 +2123,11 @@
|
|||
return false;
|
||||
}
|
||||
|
||||
if(sessionModel.areControlsLockedForJamTrackRecording() && $control.closest('.session-track').data('track_data').type == 'jam_track') {
|
||||
context.JK.prodBubble($control, 'jamtrack-controls-disabled', {}, {positions:['bottom'], offsetParent: $control.closest('.screen')})
|
||||
return false;
|
||||
}
|
||||
|
||||
if($control.data('showHelpAboutMediaMixers')) {
|
||||
if(!sessionModel.hasShownAudioMediaMixerHelp()) {
|
||||
context.JK.prodBubble($control, 'volume-media-mixers', {}, {positions:['bottom'], offsetParent: $control.closest('.screen')})
|
||||
|
|
@ -2079,6 +2135,8 @@
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
$.each(mixerIds, function(i,v) {
|
||||
var mixerId = v;
|
||||
// behavior: if this is the user's track in personal mode, then we mute the track globally
|
||||
|
|
@ -2316,6 +2374,14 @@
|
|||
$('#recording-status').text("Make a Recording");
|
||||
}
|
||||
|
||||
function lockControlsforJamTrackRecording() {
|
||||
sessionModel.lockControlsforJamTrackRecording();
|
||||
}
|
||||
|
||||
function unlockControlsforJamTrackRecording() {
|
||||
sessionModel.unlockControlsforJamTrackRecording();
|
||||
}
|
||||
|
||||
function displayWhoCreated(clientId) {
|
||||
if(app.clientId != clientId) { // don't show to creator
|
||||
sessionModel.findUserBy({clientId: clientId})
|
||||
|
|
@ -2382,7 +2448,69 @@
|
|||
return false;
|
||||
}
|
||||
|
||||
app.layout.showDialog('open-jam-track-dialog');
|
||||
app.layout.showDialog('open-jam-track-dialog').one(EVENTS.DIALOG_CLOSED, function(e, data) {
|
||||
|
||||
// once the dialog is closed, see if the user has a jamtrack selected
|
||||
if(!data.canceled && data.result.jamTrack) {
|
||||
|
||||
var jamTrack = data.result.jamTrack;
|
||||
|
||||
// hide 'other audio' placeholder
|
||||
otherAudioFilled();
|
||||
|
||||
if(downloadJamTrack) {
|
||||
// if there was one showing before somehow, destroy it.
|
||||
logger.warn("destroying existing JamTrack")
|
||||
downloadJamTrack.root.remove();
|
||||
downloadJamTrack.destroy();
|
||||
downloadJamTrack = null
|
||||
}
|
||||
|
||||
downloadJamTrack = new context.JK.DownloadJamTrack(app, jamTrack, 'large');
|
||||
|
||||
// the widget indicates when it gets to any transition; we can hide it once it reaches completion
|
||||
$(downloadJamTrack).on(EVENTS.JAMTRACK_DOWNLOADER_STATE_CHANGED, function(e, data) {
|
||||
|
||||
if(data.state == downloadJamTrack.states.synchronized) {
|
||||
logger.debug("jamtrack synchronized; hide widget and show tracks")
|
||||
downloadJamTrack.root.remove();
|
||||
downloadJamTrack.destroy();
|
||||
downloadJamTrack = null;
|
||||
|
||||
// XXX: test with this removed; it should be unnecessary
|
||||
context.jamClient.JamTrackStopPlay();
|
||||
|
||||
if(jamTrack.jmep)
|
||||
{
|
||||
logger.debug("setting jmep data")
|
||||
context.jamClient.JamTrackLoadJmep(jamTrack.id, jamTrack.jmep)
|
||||
}
|
||||
else {
|
||||
logger.debug("no jmep data for jamtrack")
|
||||
}
|
||||
|
||||
// JamTrackPlay means 'load'
|
||||
var result = context.jamClient.JamTrackPlay(jamTrack.id);
|
||||
|
||||
if(!result) {
|
||||
app.notify(
|
||||
{ title: "JamTrack Can Not Open",
|
||||
text: "Unable to open your JamTrack. Please contact support@jamkazam.com"
|
||||
}, null, true);
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// show it on the page
|
||||
$otherAudioContainer.append(downloadJamTrack.root)
|
||||
|
||||
// kick off the download JamTrack process
|
||||
downloadJamTrack.init()
|
||||
}
|
||||
else {
|
||||
logger.debug("OpenJamTrack dialog closed with no selection; ignoring", data)
|
||||
}
|
||||
})
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
@ -2497,7 +2625,7 @@
|
|||
if(sessionModel.recordedTracks()) {
|
||||
closeRecording();
|
||||
}
|
||||
else if(sessionModel.jamTracks()) {
|
||||
else if(sessionModel.jamTracks() || downloadJamTrack) {
|
||||
closeJamTrack();
|
||||
}
|
||||
else if(sessionModel.backingTrack() && sessionModel.backingTrack().path) {
|
||||
|
|
@ -2533,6 +2661,20 @@
|
|||
}
|
||||
|
||||
function closeJamTrack() {
|
||||
|
||||
logger.debug("closing recording");
|
||||
|
||||
if(downloadJamTrack) {
|
||||
logger.debug("closing DownloadJamTrack widget")
|
||||
downloadJamTrack.root.remove();
|
||||
downloadJamTrack.destroy();
|
||||
downloadJamTrack = null;
|
||||
|
||||
// this is necessary because a syncing widget means no jamtracks are loaded;
|
||||
// so removing the widget will not cause a backend media change event (and so renderSession will not be called, ultimately)
|
||||
resetOtherAudioContent();
|
||||
}
|
||||
|
||||
rest.closeJamTrack({id: sessionModel.id()})
|
||||
.done(function() {
|
||||
sessionModel.refreshCurrentSession(true);
|
||||
|
|
@ -2567,6 +2709,8 @@
|
|||
}
|
||||
|
||||
function closeRecording() {
|
||||
logger.debug("closing recording");
|
||||
|
||||
rest.stopPlayClaimedRecording({id: sessionModel.id(), claimed_recording_id: sessionModel.getCurrentSession().claimed_recording.id})
|
||||
.done(function(response) {
|
||||
//sessionModel.refreshCurrentSession(true);
|
||||
|
|
@ -2598,10 +2742,28 @@
|
|||
|
||||
function onChangePlayPosition(e, data){
|
||||
logger.debug("calling jamClient.SessionTrackSeekMs(" + data.positionMs + ")");
|
||||
|
||||
if(data.jamTrackMode) {
|
||||
context.jamClient.SessionJamTrackSeekMs(data.positionMs);
|
||||
}
|
||||
else {
|
||||
context.jamClient.SessionTrackSeekMs(data.positionMs);
|
||||
}
|
||||
}
|
||||
|
||||
function startStopRecording() {
|
||||
|
||||
// check first if a jamtrack is loaded, and playing; if so, tell user to stop the play
|
||||
if(sessionModel.jamTracks() && context.jamClient.isSessionTrackPlaying()) {
|
||||
app.notify(
|
||||
{ title: "Can't Recording a Play JamTrack",
|
||||
text: "Stop the JamTrack before trying to recording." },
|
||||
null,
|
||||
true);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if(sessionModel.recordingModel.isRecording()) {
|
||||
sessionModel.recordingModel.stopRecording();
|
||||
}
|
||||
|
|
@ -2720,6 +2882,9 @@
|
|||
$screen = $('#session-screen');
|
||||
$mixModeDropdown = $screen.find('select.monitor-mode')
|
||||
$templateMixerModeChange = $('#template-mixer-mode-change');
|
||||
$otherAudioContainer = $('#session-recordedtracks-container');
|
||||
$myTracksContainer = $('#session-mytracks-container')
|
||||
$liveTracksContainer = $('#session-livetracks-container');
|
||||
$closePlaybackRecording = $('#close-playback-recording')
|
||||
$openBackingTrack = $('#open-a-backingtrack');
|
||||
events();
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@
|
|||
var previousBackingTracks = [];
|
||||
var openBackingTrack = null;
|
||||
var shownAudioMediaMixerHelp = false;
|
||||
var controlsLockedForJamTrackRecording = false;
|
||||
|
||||
var mixerMode = MIX_MODES.PERSONAL;
|
||||
|
||||
|
|
@ -113,6 +114,11 @@
|
|||
}
|
||||
}
|
||||
|
||||
// did I open up the current JamTrack?
|
||||
function selfOpenedJamTracks() {
|
||||
return currentSession && (currentSession.jam_track_initiator_id == context.JK.currentUserId)
|
||||
}
|
||||
|
||||
function backingTrack() {
|
||||
if(currentSession) {
|
||||
// TODO: objectize this for VRFS-2665, VRFS-2666, VRFS-2667, VRFS-2668
|
||||
|
|
@ -152,6 +158,18 @@
|
|||
return inSession;
|
||||
}
|
||||
|
||||
function lockControlsforJamTrackRecording() {
|
||||
controlsLockedForJamTrackRecording = true;
|
||||
}
|
||||
|
||||
function unlockControlsforJamTrackRecording() {
|
||||
controlsLockedForJamTrackRecording = false;
|
||||
}
|
||||
|
||||
function areControlsLockedForJamTrackRecording() {
|
||||
return controlsLockedForJamTrackRecording;
|
||||
}
|
||||
|
||||
function onMixerModeChanged(newMixerMode)
|
||||
{
|
||||
mixerMode = newMixerMode;
|
||||
|
|
@ -352,6 +370,7 @@
|
|||
previousBackingTracks = []
|
||||
openBackingTrack = null
|
||||
shownAudioMediaMixerHelp = false
|
||||
controlsLockedForJamTrackRecording = false;
|
||||
}
|
||||
|
||||
// you should only update currentSession with this function
|
||||
|
|
@ -830,6 +849,10 @@
|
|||
this.isMasterMixMode = isMasterMixMode;
|
||||
this.isPersonalMixMode = isPersonalMixMode;
|
||||
this.getMixMode = getMixMode;
|
||||
this.selfOpenedJamTracks = selfOpenedJamTracks;
|
||||
this.areControlsLockedForJamTrackRecording = areControlsLockedForJamTrackRecording;
|
||||
this.lockControlsforJamTrackRecording = lockControlsforJamTrackRecording;
|
||||
this.unlockControlsforJamTrackRecording = unlockControlsforJamTrackRecording;
|
||||
|
||||
// ALERT HANDLERS
|
||||
this.onBackendMixerChanged = onBackendMixerChanged;
|
||||
|
|
|
|||
|
|
@ -84,6 +84,7 @@ class SubscriptionUtils
|
|||
# call subscribe, and use the returned object to listen for events of name context.JK.EVENTS.SUBSCRIBE_NOTIFICATION
|
||||
subscribe: (type, id) =>
|
||||
|
||||
id = id.toString()
|
||||
key = this.genKey(type, id)
|
||||
|
||||
@logger.debug("subscribing for any notifications for #{key}")
|
||||
|
|
@ -104,6 +105,7 @@ class SubscriptionUtils
|
|||
# TODO: this should not send a unsubscribe message to the server it's the last listener for the specific type/id combo
|
||||
unsubscribe: (type, id) =>
|
||||
|
||||
id = id.toString()
|
||||
key = this.genKey(type, id)
|
||||
|
||||
@logger.debug("unsubscribing for any notifications for #{key}")
|
||||
|
|
|
|||
|
|
@ -910,6 +910,10 @@
|
|||
return null;
|
||||
}
|
||||
|
||||
context.JK.makeAbsolute = function(path) {
|
||||
return window.location.protocol + '//' + window.location.host + path;
|
||||
}
|
||||
|
||||
context.JK.popExternalLinks = function ($parent) {
|
||||
|
||||
if(!$parent) $parent = $('body');
|
||||
|
|
|
|||
|
|
@ -168,6 +168,40 @@
|
|||
|
||||
.thanks-panel {
|
||||
padding: 30px;
|
||||
|
||||
span.notice {
|
||||
font-style:italic;
|
||||
font-size:12px;
|
||||
}
|
||||
|
||||
br.purchase-downloads {
|
||||
clear:both;
|
||||
margin-bottom:20px;
|
||||
}
|
||||
|
||||
.thanks-detail.purchased-jam-track {
|
||||
|
||||
margin-top:20px;
|
||||
|
||||
.purchased-jam-track-header {
|
||||
font-size: 15px;
|
||||
margin-bottom:10px;
|
||||
}
|
||||
|
||||
ul.purchased-list {
|
||||
float:left;
|
||||
margin:20px 100px 0 20px;
|
||||
|
||||
li {
|
||||
margin:0;
|
||||
}
|
||||
}
|
||||
|
||||
.download-jamtrack {
|
||||
width:auto;
|
||||
vertical-align: middle; // to make bullets mid-align when error shows
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.order-panel {
|
||||
|
|
|
|||
|
|
@ -66,4 +66,5 @@
|
|||
*= require jquery.Jcrop
|
||||
*= require icheck/minimal/minimal
|
||||
*= require users/syncViewer
|
||||
*= require ./downloadJamTrack
|
||||
*/
|
||||
|
|
@ -1,5 +1,77 @@
|
|||
@import "client/common";
|
||||
|
||||
.download-jamtrack {
|
||||
display:inline-block;
|
||||
width:100%;
|
||||
|
||||
.retry-button {
|
||||
margin-top:20px;
|
||||
}
|
||||
|
||||
.retry {
|
||||
margin-top:10px;
|
||||
}
|
||||
|
||||
.msg {
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.spinner-large {
|
||||
margin:20px auto 0;
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
.small {
|
||||
.state {
|
||||
text-align:left;
|
||||
}
|
||||
font-size:inherit;
|
||||
.msg {
|
||||
line-height: 32px;
|
||||
height: 32px;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.spinner-small {
|
||||
display:inline-block;
|
||||
vertical-align:middle;
|
||||
}
|
||||
}
|
||||
|
||||
.large {
|
||||
.state {
|
||||
text-align:center;
|
||||
}
|
||||
}
|
||||
|
||||
&.active {
|
||||
|
||||
.small {
|
||||
margin-bottom:5px;
|
||||
|
||||
.msg {
|
||||
font-weight:bold;
|
||||
color:white;
|
||||
display:inline;
|
||||
}
|
||||
.errormsg {
|
||||
display:block;
|
||||
font-size:14px;
|
||||
}
|
||||
.retry {
|
||||
display:block;
|
||||
margin:3px 0 0 0;
|
||||
font-size:14px;
|
||||
}
|
||||
.retry-button {
|
||||
float:right;
|
||||
margin:5px 0 5px 20px;
|
||||
}
|
||||
|
||||
.msg-holder {
|
||||
display:block;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -148,6 +148,17 @@
|
|||
}
|
||||
}
|
||||
|
||||
.session-recording-name {
|
||||
width:60%;
|
||||
overflow:hidden;
|
||||
margin-top:9px;
|
||||
margin-bottom:8px;
|
||||
font-size:16px;
|
||||
}
|
||||
|
||||
.download-jamtrack {
|
||||
margin-top:50px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -58,14 +58,22 @@ class ApiJamTracksController < ApiController
|
|||
end
|
||||
|
||||
def keys
|
||||
jamtrack_ids = params[:jamtracks]
|
||||
|
||||
unless jamtrack_ids.kind_of?(Array)
|
||||
render :json => {message: 'jamtracks parameter must be an array'}, :status => 200
|
||||
jamtrack_holder = params[:jamtracks]
|
||||
|
||||
unless jamtrack_holder.kind_of?(Hash)
|
||||
render :json => {message: 'jamtracks parameter must be an hash'}, :status => 422
|
||||
return
|
||||
end
|
||||
|
||||
@jam_tracks = JamTrackRight.list_keys(current_user, params[:jamtracks])
|
||||
jamtrack_ids = jamtrack_holder[:tracks]
|
||||
|
||||
unless jamtrack_ids.kind_of?(Array)
|
||||
render :json => {message: 'jamtracks:tracks parameter must be an array'}, :status => 422
|
||||
return
|
||||
end
|
||||
|
||||
@jam_tracks = JamTrackRight.list_keys(current_user, jamtrack_ids)
|
||||
|
||||
render "api_jam_tracks/list_keys", :layout => nil
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
class ApiRecordingsController < ApiController
|
||||
before_filter :api_signed_in_user, :except => [ :add_like ]
|
||||
|
||||
before_filter :lookup_recording, :only => [ :show, :stop, :claim, :discard, :keep, :delete_claim ]
|
||||
before_filter :lookup_recording, :only => [ :show, :stop, :claim, :discard, :keep, :delete_claim, :add_timeline_data ]
|
||||
before_filter :lookup_recorded_track, :only => [ :download, :upload_next_part, :upload_sign, :upload_part_complete, :upload_complete ]
|
||||
before_filter :lookup_recorded_backing_track, :only => [ :backing_track_download, :backing_track_upload_next_part, :backing_track_upload_sign, :backing_track_upload_part_complete, :backing_track_upload_complete ]
|
||||
before_filter :lookup_recorded_video, :only => [ :video_upload_sign, :video_upload_start, :video_upload_complete ]
|
||||
|
|
@ -377,6 +377,13 @@ class ApiRecordingsController < ApiController
|
|||
end
|
||||
end
|
||||
|
||||
# metadata
|
||||
def add_timeline
|
||||
@recording.add_timeline(params[:metadata])
|
||||
|
||||
render :json => {}, :status => 200
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def lookup_recording
|
||||
|
|
|
|||
|
|
@ -57,20 +57,36 @@ class ApiRecurlyController < ApiController
|
|||
def place_order
|
||||
error=nil
|
||||
puts "PLACING ORDER #{params.inspect}"
|
||||
response = {jam_tracks:[]}
|
||||
|
||||
# 1st confirm that all specified JamTracks exist
|
||||
jam_tracks = []
|
||||
|
||||
params[:jam_tracks].each do |jam_track_id|
|
||||
jam_track = JamTrack.where("id=?", jam_track_id).first
|
||||
if jam_track
|
||||
@client.place_order(current_user, jam_track)
|
||||
jam_tracks << jam_track
|
||||
else
|
||||
error="JamTrack not found for '#{jam_track_id}'"
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
# then buy each
|
||||
unless error
|
||||
jam_tracks.each do |jam_track|
|
||||
jam_track_right = @client.place_order(current_user, jam_track)
|
||||
# build up the response object with JamTracks that were purchased.
|
||||
# if this gets more complicated, we should switch to RABL
|
||||
response[:jam_tracks] << {name: jam_track.name, id: jam_track.id, jam_track_right_id: jam_track_right.id}
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
if error
|
||||
render json: { errors: {message:error}}, :status => 404
|
||||
else
|
||||
render :json=>{}, :status=>200
|
||||
render :json=>response, :status=>200
|
||||
end
|
||||
rescue RecurlyClientError => x
|
||||
render json: { message: x.inspect, errors: x.errors}, :status => 404
|
||||
|
|
|
|||
|
|
@ -33,11 +33,26 @@ class SpikesController < ApplicationController
|
|||
|
||||
def subscription
|
||||
|
||||
#Notification.send_reload(MessageFactory::ALL_NATIVE_CLIENTS)
|
||||
|
||||
Notification.send_subscription_message('test', '1', '{"msg": "oh hai 1"}')
|
||||
Notification.send_subscription_message('test', '2', '{"msg": "oh hai 2"}')
|
||||
render text: 'oh hai'
|
||||
end
|
||||
|
||||
def download_jam_track
|
||||
|
||||
jamTrack = JamTrack.find(params[:jam_track_id])
|
||||
jamTrackRight = jamTrack.right_for_user(current_user)
|
||||
|
||||
gon.jamTrackId = jamTrack.id
|
||||
gon.jamTrackRightId = jamTrackRight.id
|
||||
gon.size = params[:size] ? params[:size] : 'large'
|
||||
gon.switchState = params[:state]
|
||||
|
||||
render :layout => 'web'
|
||||
end
|
||||
|
||||
def site_validate
|
||||
render :layout => 'web'
|
||||
end
|
||||
|
|
@ -45,5 +60,4 @@ class SpikesController < ApplicationController
|
|||
def recording_source
|
||||
render :layout => 'web'
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -20,8 +20,16 @@ node :mix do |claimed_recording|
|
|||
end
|
||||
|
||||
child(:recording => :recording) {
|
||||
attributes :id, :created_at, :duration, :comment_count, :like_count, :play_count
|
||||
|
||||
attributes :id, :created_at, :duration, :comment_count, :like_count, :play_count, :jam_track_id, :jam_track_initiator_id
|
||||
|
||||
child(:jam_track => :jam_track) {
|
||||
attributes :id
|
||||
|
||||
node :jmep do |jam_track|
|
||||
jam_track.jmep_json ? JSON.parse(jam_track.jmep_json) : nil
|
||||
end
|
||||
}
|
||||
|
||||
child(:band => :band) {
|
||||
attributes :id, :name, :location, :photo_url
|
||||
}
|
||||
|
|
@ -50,6 +58,15 @@ child(:recording => :recording) {
|
|||
end
|
||||
}
|
||||
|
||||
child(:recorded_jam_track_tracks => :recorded_jam_track_tracks) {
|
||||
node do |recorded_jam_track_track|
|
||||
{
|
||||
id: recorded_jam_track_track.jam_track_track.id,
|
||||
timeline: recorded_jam_track_track.timeline ? JSON.parse(recorded_jam_track_track.timeline) : []
|
||||
}
|
||||
end
|
||||
}
|
||||
|
||||
child(:comments => :comments) {
|
||||
attributes :comment, :created_at
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ object @jam_tracks
|
|||
|
||||
node do |jam_track|
|
||||
{
|
||||
id: jam_track['id'],
|
||||
id: jam_track['id'].to_s,
|
||||
private: jam_track['private_key'],
|
||||
error: jam_track['private_key'] ? nil : ( jam_track['jam_track_right_id'] ? 'no_key' : 'not_purchased' )
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
object @jam_track
|
||||
|
||||
attributes :id, :name, :description, :recording_type, :original_artist, :songwriter, :publisher, :sales_region, :price
|
||||
attributes :id, :name, :description, :recording_type, :original_artist, :songwriter, :publisher, :sales_region, :price, :version
|
||||
|
||||
node :genres do |item|
|
||||
[item.genre.description] # XXX: need to return single genre; not array
|
||||
|
|
|
|||
|
|
@ -1,6 +1,14 @@
|
|||
object @jam_track
|
||||
|
||||
attributes :id, :name, :description, :initial_play_silence, :original_artist
|
||||
attributes :id, :name, :description, :initial_play_silence, :original_artist, :version
|
||||
|
||||
node :jmep do |jam_track|
|
||||
jam_track.jmep_json ? JSON.parse(jam_track.jmep_json) : nil
|
||||
end
|
||||
|
||||
node :jam_track_right_id do |jam_track|
|
||||
jam_track.right_for_user(current_user).id
|
||||
end
|
||||
|
||||
child(:jam_track_tracks => :tracks) {
|
||||
attributes :id, :part, :instrument
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ if !current_user
|
|||
}
|
||||
else
|
||||
|
||||
attributes :id, :name, :description, :musician_access, :approval_required, :fan_access, :fan_chat, :band_id, :user_id, :claimed_recording_initiator_id, :track_changes_counter, :max_score, :backing_track_path, :metronome_active
|
||||
attributes :id, :name, :description, :musician_access, :approval_required, :fan_access, :fan_chat, :band_id, :user_id, :claimed_recording_initiator_id, :track_changes_counter, :max_score, :backing_track_path, :metronome_active, :jam_track_initiator_id
|
||||
|
||||
node :can_join do |session|
|
||||
session.can_join?(current_user, true)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
object @recording
|
||||
|
||||
attributes :id, :band, :created_at, :duration, :comment_count, :like_count, :play_count, :when_will_be_discarded?
|
||||
attributes :id, :band, :created_at, :duration, :comment_count, :like_count, :play_count, :when_will_be_discarded?, :jam_track_id, :jam_track_initiator_id
|
||||
|
||||
node :mix do |recording|
|
||||
if recording.mix
|
||||
|
|
@ -12,6 +12,13 @@ node :mix do |recording|
|
|||
end
|
||||
end
|
||||
|
||||
child(:jam_track => :jam_track) {
|
||||
attributes :id
|
||||
|
||||
node :jmep do |jam_track|
|
||||
jam_track.jmep_json ? JSON.parse(jam_track.jmep_json) : nil
|
||||
end
|
||||
}
|
||||
|
||||
child(:band => :band) {
|
||||
attributes :id, :name, :location, :photo_url
|
||||
|
|
@ -33,6 +40,15 @@ child(:recorded_backing_tracks => :recorded_backing_tracks) {
|
|||
end
|
||||
}
|
||||
|
||||
child(:recorded_jam_track_tracks => :recorded_jam_track_tracks) {
|
||||
node do |recorded_jam_track_track|
|
||||
{
|
||||
id: recorded_jam_track_track.jam_track_track.id,
|
||||
timeline: recorded_jam_track_track.timeline ? JSON.parse(recorded_jam_track_track.timeline) : []
|
||||
}
|
||||
end
|
||||
}
|
||||
|
||||
child(:comments => :comments) {
|
||||
attributes :comment, :created_at
|
||||
|
||||
|
|
|
|||
|
|
@ -1,2 +1,86 @@
|
|||
script type="text/template" id='template-download-jamtrack'
|
||||
.download-jamtrack
|
||||
.state
|
||||
|
||||
script type="text/template" id="template-download-jamtrack-state-no-client"
|
||||
.state-no-client
|
||||
.large.hidden
|
||||
.msg
|
||||
| To play your JamTrack, launch the JamKazam application and open the JamTrack while in a session.
|
||||
.small.hidden
|
||||
.msg
|
||||
| {{data.name}} (launch client)
|
||||
|
||||
script type="text/template" id="template-download-jamtrack-state-synchronized"
|
||||
.state-synchronized
|
||||
.large.hidden
|
||||
.msg
|
||||
| Your JamTrack is on your system and ready to play.
|
||||
.small.hidden
|
||||
.msg
|
||||
| {{data.name}} (done)
|
||||
|
||||
script type="text/template" id="template-download-jamtrack-state-packaging"
|
||||
.state-packaging
|
||||
.large.hidden
|
||||
.msg
|
||||
| Your JamTrack is currently being created on the JamKazam server.
|
||||
.spinner-large
|
||||
.small.hidden
|
||||
.msg
|
||||
| {{data.name}} (packaging)
|
||||
.spinner-small
|
||||
|
||||
script type="text/template" id="template-download-jamtrack-state-downloading"
|
||||
.state-downloading
|
||||
.large.hidden
|
||||
.msg
|
||||
| Your JamTrack is currently being downloaded.
|
||||
.spinner-large
|
||||
.small.hidden
|
||||
.msg
|
||||
| {{data.name}} (downloading)
|
||||
.spinner-small
|
||||
|
||||
script type="text/template" id="template-download-jamtrack-state-keying"
|
||||
.state-keying
|
||||
.large.hidden
|
||||
.msg
|
||||
| Your JamTrack is being authenticated.
|
||||
.spinner-large
|
||||
.small.hidden
|
||||
.msg
|
||||
| {{data.name}} (keying)
|
||||
.spinner-small
|
||||
|
||||
script type="text/template" id="template-download-jamtrack-state-initial"
|
||||
.state-initial
|
||||
.large.hidden
|
||||
.msg
|
||||
| Initializing JamTrack...
|
||||
.spinner-large
|
||||
.small.hidden
|
||||
.msg
|
||||
| {{data.name}} (initializing)
|
||||
.spinner-small
|
||||
|
||||
script type="text/template" id="template-download-jamtrack-state-quiet"
|
||||
.state-quiet
|
||||
.large.hidden
|
||||
.msg
|
||||
.small.hidden
|
||||
.msg
|
||||
| {{data.name}} (pending)
|
||||
|
||||
script type="text/template" id="template-download-jamtrack-state-errored"
|
||||
.state-errored
|
||||
.large.hidden
|
||||
.msg
|
||||
.retry
|
||||
a.button-orange.retry-button RETRY
|
||||
.small.hidden
|
||||
.msg-holder
|
||||
.msg
|
||||
a.button-orange.retry-button RETRY
|
||||
.errormsg
|
||||
.retry
|
||||
|
|
|
|||
|
|
@ -199,6 +199,9 @@ script type="text/template" id="template-help-media-controls-disabled"
|
|||
| Only the person who opened the recording can control the volume levels.
|
||||
| {% } %}
|
||||
|
||||
script type="text/template" id="template-help-jamtrack-controls-disabled"
|
||||
| During a recording, volume and mute controls for JamTracks are disabled. So, get the session volume levels right before starting the recording.
|
||||
|
||||
|
||||
script type="text/template" id="template-help-volume-media-mixers"
|
||||
| Audio files only expose both master and personal mix controls, so any change here will also affect everyone in the session.
|
||||
|
|
|
|||
|
|
@ -178,8 +178,15 @@ div layout="screen" layout-id="order" id="orderScreen" class="screen secondary"
|
|||
br
|
||||
.thanks-detail We'll send you an email confirming your order shortly.
|
||||
br
|
||||
.thanks-detail If you purchased any JamTracks, the next time you run the JamKazam application, your JamTracks will automatically be downloaded to the app, and you will receive a notification when the download is complete.
|
||||
|
||||
.thanks-detail.jam-tracks-in-browser.hidden
|
||||
| To play your purchased JamTrack, launch the JamKazam application and open the JamTrack while in a session.
|
||||
.thanks-detail.purchased-jam-track.hidden
|
||||
h2.purchased-jam-track-header Downloading Your Purchased JamTracks
|
||||
span Each JamTrack will be downloaded sequentially.
|
||||
br
|
||||
span.notice Note that you do not have to wait for this to complete in order to use your JamTrack later.
|
||||
br.clear
|
||||
ul.purchased-list
|
||||
|
||||
|
||||
|
||||
|
|
@ -276,4 +283,7 @@ script type='text/template' id='template-order-content'
|
|||
span and
|
||||
'
|
||||
a href="http://www.jamkazam.com/corp/returns" returns policy
|
||||
span .
|
||||
span .
|
||||
|
||||
script type='text/template' id='template-purchased-jam-track'
|
||||
li data-jam-track-id="{{data.jam_track_id}}"
|
||||
|
|
@ -71,7 +71,7 @@
|
|||
| other audio
|
||||
.session-recording-name-wrapper
|
||||
.session-recording-name.left
|
||||
| (No recording loaded)
|
||||
| (No audio loaded)
|
||||
.session-add.right
|
||||
a#close-playback-recording[href="#"]
|
||||
= image_tag "content/icon_close.png", {:width => 18, :height => 20, :align => "texttop"}
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@
|
|||
<%= render "overlay_small" %>
|
||||
<%= render "listenBroadcast" %>
|
||||
<%= render "sync_viewer_templates" %>
|
||||
<%= render "download_jamtrack_templates" %>
|
||||
<%= render "help" %>
|
||||
<%= render 'dialogs/dialogs' %>
|
||||
<div id="fb-root"></div>
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@
|
|||
a href='/client#/jamtrack' rel="external"
|
||||
| Shop for JamTracks
|
||||
.right
|
||||
a href="#" class="button-grey" layout-action="close"
|
||||
a href="#" class="button-grey" layout-action="cancel"
|
||||
| CANCEL
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,44 @@
|
|||
= javascript_include_tag "download_jamtrack"
|
||||
= render "clients/download_jamtrack_templates"
|
||||
= stylesheet_link_tag "client/downloadJamTrack"
|
||||
|
||||
- provide(:title, 'Download Jam Track Widget')
|
||||
|
||||
.content-wrapper
|
||||
h2 Jam Track State Widget
|
||||
|
||||
h3 Possible States
|
||||
ul
|
||||
li synchronized
|
||||
li no_client
|
||||
li packaging
|
||||
li downloading
|
||||
li keying
|
||||
li initial
|
||||
li errored
|
||||
#widget
|
||||
|
||||
javascript:
|
||||
var initialized = false;
|
||||
$(document).on('JAMKAZAM_READY', function(e, data) {
|
||||
window.JK.JamServer.get$Server().on(window.JK.EVENTS.CONNECTION_UP, function() {
|
||||
if(initialized) {
|
||||
return;
|
||||
}
|
||||
initialized = true
|
||||
|
||||
setTimeout(function() {
|
||||
window.downloadJamTrack = new JK.DownloadJamTrack(data.app, {id: gon.jamTrackId, jam_track_right_id: gon.jamTrackRightId, name: 'Back in Black'}, gon.size)
|
||||
downloadJamTrack.init()
|
||||
$('#widget').append(window.downloadJamTrack.root)
|
||||
|
||||
if (gon.switchState == 'errored') {
|
||||
downloadJamTrack.transitionError("package-error", "The server failed to create your package.")
|
||||
}
|
||||
else if (gon.switchState) {
|
||||
downloadJamTrack.transition(downloadJamTrack.states[gon.switchState]);
|
||||
}
|
||||
}, 1)
|
||||
|
||||
})
|
||||
})
|
||||
|
|
@ -209,6 +209,8 @@ if defined?(Bundler)
|
|||
|
||||
# Location of jamtracks python tool:
|
||||
config.jamtracks_dir = ENV['JAMTRACKS_DIR'] || File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "..", "jamtracks"))
|
||||
config.jmep_dir = ENV['JMEP_DIR'] || File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "..", "jmep"))
|
||||
|
||||
# amount of time before we think packaging job is broken
|
||||
config.signing_job_run_max_time = 60 # 1 minute
|
||||
# amount of time before we think the queue is stuck
|
||||
|
|
@ -310,6 +312,7 @@ if defined?(Bundler)
|
|||
config.influxdb_port = 8086
|
||||
config.influxdb_ignored_environments = ENV["INFLUXDB_ENABLED"] == '1' ? ['test', 'cucumber'] : ['test', 'cucumber', 'development']
|
||||
|
||||
config.allow_spikes = false
|
||||
config.show_jamblaster_notice = true
|
||||
config.show_jamblaster_kickstarter_link = true
|
||||
config.metronome_available = true
|
||||
|
|
|
|||
|
|
@ -81,21 +81,20 @@ SampleApp::Application.routes.draw do
|
|||
|
||||
match '/endorse/:id/:service', to: 'users#endorse', :as => 'endorse'
|
||||
|
||||
# temporarily allow for debugging--only allows admini n
|
||||
match '/listen_in', to: 'spikes#listen_in'
|
||||
|
||||
# embed resque-web if this is development mode
|
||||
if Rails.env == "development"
|
||||
if Rails.env == "development" || Rails.application.config.allow_spikes
|
||||
require 'resque/server'
|
||||
require 'resque-retry'
|
||||
require 'resque-retry/server'
|
||||
mount Resque::Server.new, :at => "/resque" if Rails.env == "development"
|
||||
|
||||
# route to spike controller (proof-of-concepts)
|
||||
match '/listen_in', to: 'spikes#listen_in'
|
||||
match '/facebook_invite', to: 'spikes#facebook_invite'
|
||||
match '/launch_app', to: 'spikes#launch_app'
|
||||
match '/websocket', to: 'spikes#websocket'
|
||||
match '/test_subscription', to: 'spikes#subscription'
|
||||
match '/widgets/download_jam_track', to: 'spikes#download_jam_track'
|
||||
match '/site_validate', to: 'spikes#site_validate'
|
||||
match '/recording_source', to: 'spikes#recording_source'
|
||||
|
||||
|
|
@ -210,7 +209,7 @@ SampleApp::Application.routes.draw do
|
|||
match '/jamtracks/downloads' => 'api_jam_tracks#downloads', :via => :get, :as => 'api_jam_tracks_downloads'
|
||||
match '/jamtracks/download/:id' => 'api_jam_tracks#download', :via => :get, :as => 'api_jam_tracks_download'
|
||||
match '/jamtracks/enqueue/:id' => 'api_jam_tracks#enqueue', :via => :post, :as => 'api_jam_tracks_enqueue'
|
||||
match '/jamtracks/show/:id' => 'api_jam_tracks#show_jam_track_right', :via => :get, :as => 'api_jam_tracks_show_right'
|
||||
match '/jamtracks/rights/:id' => 'api_jam_tracks#show_jam_track_right', :via => :get, :as => 'api_jam_tracks_show_right'
|
||||
match '/jamtracks/keys' => 'api_jam_tracks#keys', :via => :post, :as => 'api_jam_tracks_keys'
|
||||
|
||||
# Shopping carts
|
||||
|
|
@ -452,6 +451,7 @@ SampleApp::Application.routes.draw do
|
|||
match '/recordings/:id/comments' => 'api_recordings#add_comment', :via => :post, :as => 'api_recordings_add_comment'
|
||||
match '/recordings/:id/likes' => 'api_recordings#add_like', :via => :post, :as => 'api_recordings_add_like'
|
||||
match '/recordings/:id/discard' => 'api_recordings#discard', :via => :post, :as => 'api_recordings_discard'
|
||||
match '/recordings/:id/timeline' => 'api_recordings#add_timeline', :via => :post, :as => 'api_recordings_timeline'
|
||||
|
||||
# Recordings - recorded_tracks
|
||||
match '/recordings/:id/tracks/:track_id' => 'api_recordings#show_recorded_track', :via => :get, :as => 'api_recordings_show_recorded_track'
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
require 'factory_girl'
|
||||
require 'open-uri'
|
||||
|
||||
#require './spec/factories.rb' # useful when run on a server
|
||||
|
||||
namespace :db do
|
||||
desc "Add a simple one track recording to the database"
|
||||
|
|
|
|||
|
|
@ -102,6 +102,7 @@ describe ApiJamTracksController do
|
|||
response.should be_success
|
||||
json = JSON.parse(response.body)
|
||||
json['jamtracks'].length.should eq(1)
|
||||
json['jamtracks'][0]['jam_track_right_id'].should eq(right.id)
|
||||
json['next'].should be_nil
|
||||
end
|
||||
end
|
||||
|
|
@ -196,18 +197,18 @@ describe ApiJamTracksController do
|
|||
|
||||
describe "keys" do
|
||||
it "empty" do
|
||||
get :keys, jamtracks: []
|
||||
get :keys, jamtracks: {tracks: []}
|
||||
response.status.should == 200
|
||||
json = JSON.parse(response.body)
|
||||
json.length == 0
|
||||
end
|
||||
|
||||
it "track with no rights" do
|
||||
get :keys, jamtracks: [@jam_track.id]
|
||||
get :keys, jamtracks: { tracks: [@jam_track.id] }
|
||||
response.status.should == 200
|
||||
json = JSON.parse(response.body)
|
||||
json.length.should == 1
|
||||
json[0]['id'].should == @jam_track.id
|
||||
json[0]['id'].should == @jam_track.id.to_s
|
||||
json[0]['private'].should be_nil
|
||||
json[0]['error'].should == 'not_purchased'
|
||||
end
|
||||
|
|
@ -216,32 +217,32 @@ describe ApiJamTracksController do
|
|||
|
||||
right = FactoryGirl.create(:jam_track_right, user: @user, private_key: nil, jam_track: @jam_track)
|
||||
|
||||
get :keys, jamtracks: [@jam_track.id]
|
||||
get :keys, jamtracks: { tracks: [@jam_track.id] }
|
||||
response.status.should == 200
|
||||
json = JSON.parse(response.body)
|
||||
json.length.should == 1
|
||||
json[0]['id'].should == @jam_track.id
|
||||
json[0]['id'].should == @jam_track.id.to_s
|
||||
json[0]['private'].should be_nil
|
||||
json[0]['error'].should == 'no_key'
|
||||
end
|
||||
|
||||
it "track with key" do
|
||||
right = FactoryGirl.create(:jam_track_right, user: @user, private_key: 'abc', jam_track: @jam_track)
|
||||
get :keys, jamtracks: [@jam_track.id]
|
||||
get :keys, jamtracks: { tracks: [@jam_track.id] }
|
||||
response.status.should == 200
|
||||
json = JSON.parse(response.body)
|
||||
json.length.should == 1
|
||||
json[0]['id'].should == @jam_track.id
|
||||
json[0]['id'].should == @jam_track.id.to_s
|
||||
json[0]['private'].should eq('abc')
|
||||
json[0]['error'].should be_nil
|
||||
end
|
||||
|
||||
it "non-owning user asking for a real track" do
|
||||
right = FactoryGirl.create(:jam_track_right, user: FactoryGirl.create(:user), private_key: 'abc', jam_track: @jam_track)
|
||||
get :keys, jamtracks: [@jam_track.id]
|
||||
get :keys, jamtracks: { tracks: [@jam_track.id] }
|
||||
response.status.should == 200
|
||||
json = JSON.parse(response.body)
|
||||
json[0]['id'].should == @jam_track.id
|
||||
json[0]['id'].should == @jam_track.id.to_s
|
||||
json[0]['private'].should be_nil
|
||||
json[0]['error'].should == 'not_purchased'
|
||||
end
|
||||
|
|
|
|||
|
|
@ -3,217 +3,251 @@ require 'spec_helper'
|
|||
describe ApiRecordingsController do
|
||||
render_views
|
||||
|
||||
describe "recording with backing track" do
|
||||
|
||||
before(:each) do
|
||||
@user = FactoryGirl.create(:user)
|
||||
@instrument = FactoryGirl.create(:instrument, :description => 'a great instrument')
|
||||
@music_session = FactoryGirl.create(:active_music_session, :creator => @user, :musician_access => true)
|
||||
@connection = FactoryGirl.create(:connection, :user => @user, :music_session => @music_session)
|
||||
@track = FactoryGirl.create(:track, :connection => @connection, :instrument => @instrument)
|
||||
@backing_track = FactoryGirl.create(:backing_track, :connection => @connection)
|
||||
controller.current_user = @user
|
||||
end
|
||||
|
||||
describe "start" do
|
||||
it "should work" do
|
||||
post :start, { :format => 'json', :music_session_id => @music_session.id }
|
||||
response.should be_success
|
||||
response_body = JSON.parse(response.body)
|
||||
response_body['id'].should_not be_nil
|
||||
recording = Recording.find(response_body['id'])
|
||||
before(:each) do
|
||||
@user = FactoryGirl.create(:user)
|
||||
@instrument = FactoryGirl.create(:instrument, :description => 'a great instrument')
|
||||
@music_session = FactoryGirl.create(:active_music_session, :creator => @user, :musician_access => true)
|
||||
@connection = FactoryGirl.create(:connection, :user => @user, :music_session => @music_session)
|
||||
@track = FactoryGirl.create(:track, :connection => @connection, :instrument => @instrument)
|
||||
@backing_track = FactoryGirl.create(:backing_track, :connection => @connection)
|
||||
controller.current_user = @user
|
||||
end
|
||||
|
||||
it "should not allow multiple starts" do
|
||||
post :start, { :format => 'json', :music_session_id => @music_session.id }
|
||||
post :start, { :format => 'json', :music_session_id => @music_session.id }
|
||||
response.status.should == 422
|
||||
response_body = JSON.parse(response.body)
|
||||
response_body["errors"]["music_session"][0].should == ValidationMessages::ALREADY_BEING_RECORDED
|
||||
describe "start" do
|
||||
it "should work" do
|
||||
post :start, {:format => 'json', :music_session_id => @music_session.id}
|
||||
response.should be_success
|
||||
response_body = JSON.parse(response.body)
|
||||
response_body['id'].should_not be_nil
|
||||
recording = Recording.find(response_body['id'])
|
||||
end
|
||||
|
||||
it "should not allow multiple starts" do
|
||||
post :start, {:format => 'json', :music_session_id => @music_session.id}
|
||||
post :start, {:format => 'json', :music_session_id => @music_session.id}
|
||||
response.status.should == 422
|
||||
response_body = JSON.parse(response.body)
|
||||
response_body["errors"]["music_session"][0].should == ValidationMessages::ALREADY_BEING_RECORDED
|
||||
end
|
||||
|
||||
it "should not allow start while playback ongoing" do
|
||||
recording = Recording.start(@music_session, @user)
|
||||
recording.stop
|
||||
recording.reload
|
||||
claimed_recording = recording.claim(@user, "name", "description", Genre.first, true)
|
||||
@music_session.claimed_recording_start(@user, claimed_recording)
|
||||
@music_session.errors.any?.should be_false
|
||||
post :start, {:format => 'json', :music_session_id => @music_session.id}
|
||||
response.status.should == 422
|
||||
response_body = JSON.parse(response.body)
|
||||
response_body["errors"]["music_session"][0].should == ValidationMessages::ALREADY_PLAYBACK_RECORDING
|
||||
end
|
||||
|
||||
it "should not allow start by somebody not in the music session" do
|
||||
user2 = FactoryGirl.create(:user)
|
||||
controller.current_user = user2
|
||||
post :start, {:format => 'json', :music_session_id => @music_session.id}
|
||||
response.status.should == 403
|
||||
end
|
||||
end
|
||||
|
||||
it "should not allow start while playback ongoing" do
|
||||
recording = Recording.start(@music_session, @user)
|
||||
recording.stop
|
||||
recording.reload
|
||||
claimed_recording = recording.claim(@user, "name", "description", Genre.first, true)
|
||||
@music_session.claimed_recording_start(@user, claimed_recording)
|
||||
@music_session.errors.any?.should be_false
|
||||
post :start, { :format => 'json', :music_session_id => @music_session.id }
|
||||
response.status.should == 422
|
||||
response_body = JSON.parse(response.body)
|
||||
response_body["errors"]["music_session"][0].should == ValidationMessages::ALREADY_PLAYBACK_RECORDING
|
||||
describe "get" do
|
||||
it "should work" do
|
||||
post :start, {:format => 'json', :music_session_id => @music_session.id}
|
||||
response.should be_success
|
||||
response_body = JSON.parse(response.body)
|
||||
response_body['id'].should_not be_nil
|
||||
recordingId = response_body['id']
|
||||
get :show, {:format => 'json', :id => recordingId}
|
||||
response.should be_success
|
||||
response_body = JSON.parse(response.body)
|
||||
response_body['id'].should == recordingId
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
it "should not allow start by somebody not in the music session" do
|
||||
user2 = FactoryGirl.create(:user)
|
||||
controller.current_user = user2
|
||||
post :start, { :format => 'json', :music_session_id => @music_session.id }
|
||||
response.status.should == 403
|
||||
describe "stop" do
|
||||
it "should work" do
|
||||
post :start, {:format => 'json', :music_session_id => @music_session.id}
|
||||
response_body = JSON.parse(response.body)
|
||||
recording = Recording.find(response_body['id'])
|
||||
post :stop, {:format => 'json', :id => recording.id}
|
||||
response.should be_success
|
||||
response_body = JSON.parse(response.body)
|
||||
response_body['id'].should_not be_nil
|
||||
Recording.find(response_body['id']).id.should == recording.id
|
||||
end
|
||||
|
||||
it "should not allow stop on a session not being recorded" do
|
||||
post :start, {:format => 'json', :music_session_id => @music_session.id}
|
||||
response_body = JSON.parse(response.body)
|
||||
recording = Recording.find(response_body['id'])
|
||||
post :stop, {:format => 'json', :id => recording.id}
|
||||
post :stop, {:format => 'json', :id => recording.id}
|
||||
response.status.should == 422
|
||||
response_body = JSON.parse(response.body)
|
||||
end
|
||||
|
||||
it "should not allow stop on a session requested by a different member" do
|
||||
|
||||
post :start, {:format => 'json', :music_session_id => @music_session.id}
|
||||
response_body = JSON.parse(response.body)
|
||||
recording = Recording.find(response_body['id'])
|
||||
user2 = FactoryGirl.create(:user)
|
||||
controller.current_user = user2
|
||||
post :stop, {:format => 'json', :id => recording.id}
|
||||
response.status.should == 403
|
||||
end
|
||||
end
|
||||
|
||||
describe "download track" do
|
||||
let(:mix) { FactoryGirl.create(:mix) }
|
||||
|
||||
it "should only allow a user to download a track if they have claimed the recording" do
|
||||
post :start, {:format => 'json', :music_session_id => @music_session.id}
|
||||
response_body = JSON.parse(response.body)
|
||||
recording = Recording.find(response_body['id'])
|
||||
post :stop, {:format => 'json', :id => recording.id}
|
||||
response.should be_success
|
||||
end
|
||||
|
||||
|
||||
it "is possible" do
|
||||
mix.touch
|
||||
recorded_track = mix.recording.recorded_tracks[0]
|
||||
controller.current_user = mix.recording.owner
|
||||
get :download, {id: recorded_track.recording.id, track_id: recorded_track.client_track_id}
|
||||
response.status.should == 302
|
||||
|
||||
recorded_track.reload
|
||||
recorded_track.download_count.should == 1
|
||||
|
||||
get :download, {id: recorded_track.recording.id, track_id: recorded_track.client_track_id}
|
||||
response.status.should == 302
|
||||
|
||||
recorded_track.reload
|
||||
recorded_track.download_count.should == 2
|
||||
end
|
||||
|
||||
|
||||
it "prevents download after limit is reached" do
|
||||
mix.touch
|
||||
recorded_track = mix.recording.recorded_tracks[0]
|
||||
recorded_track.download_count = APP_CONFIG.max_audio_downloads
|
||||
recorded_track.save!
|
||||
controller.current_user = recorded_track.user
|
||||
get :download, {format: 'json', id: recorded_track.recording.id, track_id: recorded_track.client_track_id}
|
||||
response.status.should == 404
|
||||
JSON.parse(response.body, symbolize_names: true)[:message].should == "download limit surpassed"
|
||||
end
|
||||
|
||||
|
||||
it "lets admins surpass limit" do
|
||||
mix.touch
|
||||
recorded_track = mix.recording.recorded_tracks[0]
|
||||
recorded_track.download_count = APP_CONFIG.max_audio_downloads
|
||||
recorded_track.save!
|
||||
recorded_track.user.admin = true
|
||||
recorded_track.user.save!
|
||||
|
||||
controller.current_user = recorded_track.user
|
||||
get :download, {format: 'json', id: recorded_track.recording.id, track_id: recorded_track.client_track_id}
|
||||
response.status.should == 302
|
||||
recorded_track.reload
|
||||
recorded_track.download_count.should == 101
|
||||
end
|
||||
end
|
||||
|
||||
describe "download backing track" do
|
||||
let(:mix) { FactoryGirl.create(:mix) }
|
||||
|
||||
it "should only allow a user to download a track if they have claimed the recording" do
|
||||
post :start, {:format => 'json', :music_session_id => @music_session.id}
|
||||
response_body = JSON.parse(response.body)
|
||||
recording = Recording.find(response_body['id'])
|
||||
post :stop, {:format => 'json', :id => recording.id}
|
||||
response.should be_success
|
||||
end
|
||||
|
||||
|
||||
it "is possible" do
|
||||
mix.touch
|
||||
recorded_track = mix.recording.recorded_tracks[0]
|
||||
controller.current_user = mix.recording.owner
|
||||
get :download, {id: recorded_track.recording.id, track_id: recorded_track.client_track_id}
|
||||
response.status.should == 302
|
||||
|
||||
recorded_track.reload
|
||||
recorded_track.download_count.should == 1
|
||||
|
||||
get :download, {id: recorded_track.recording.id, track_id: recorded_track.client_track_id}
|
||||
response.status.should == 302
|
||||
|
||||
recorded_track.reload
|
||||
recorded_track.download_count.should == 2
|
||||
end
|
||||
|
||||
|
||||
it "prevents download after limit is reached" do
|
||||
mix.touch
|
||||
recorded_track = mix.recording.recorded_tracks[0]
|
||||
recorded_track.download_count = APP_CONFIG.max_audio_downloads
|
||||
recorded_track.save!
|
||||
controller.current_user = recorded_track.user
|
||||
get :download, {format: 'json', id: recorded_track.recording.id, track_id: recorded_track.client_track_id}
|
||||
response.status.should == 404
|
||||
JSON.parse(response.body, symbolize_names: true)[:message].should == "download limit surpassed"
|
||||
end
|
||||
|
||||
|
||||
it "lets admins surpass limit" do
|
||||
mix.touch
|
||||
recorded_track = mix.recording.recorded_tracks[0]
|
||||
recorded_track.download_count = APP_CONFIG.max_audio_downloads
|
||||
recorded_track.save!
|
||||
recorded_track.user.admin = true
|
||||
recorded_track.user.save!
|
||||
|
||||
controller.current_user = recorded_track.user
|
||||
get :download, {format: 'json', id: recorded_track.recording.id, track_id: recorded_track.client_track_id}
|
||||
response.status.should == 302
|
||||
recorded_track.reload
|
||||
recorded_track.download_count.should == 101
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "get" do
|
||||
it "should work" do
|
||||
post :start, { :format => 'json', :music_session_id => @music_session.id }
|
||||
response.should be_success
|
||||
response_body = JSON.parse(response.body)
|
||||
response_body['id'].should_not be_nil
|
||||
recordingId = response_body['id']
|
||||
get :show, {:format => 'json', :id => recordingId}
|
||||
response.should be_success
|
||||
response_body = JSON.parse(response.body)
|
||||
response_body['id'].should == recordingId
|
||||
describe "recording with jam track" do
|
||||
|
||||
before(:each) do
|
||||
@user = FactoryGirl.create(:user)
|
||||
@instrument = FactoryGirl.create(:instrument, :description => 'a great instrument')
|
||||
@music_session = FactoryGirl.create(:active_music_session, :creator => @user, :musician_access => true)
|
||||
@connection = FactoryGirl.create(:connection, :user => @user, :music_session => @music_session)
|
||||
@track = FactoryGirl.create(:track, :connection => @connection, :instrument => @instrument)
|
||||
@jam_track = FactoryGirl.create(:jam_track)
|
||||
|
||||
# make sure the jam track is opened
|
||||
@music_session.jam_track = @jam_track
|
||||
@music_session.jam_track_initiator = @user
|
||||
@music_session.save!
|
||||
controller.current_user = @user
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe "stop" do
|
||||
it "should work" do
|
||||
post :start, { :format => 'json', :music_session_id => @music_session.id }
|
||||
response_body = JSON.parse(response.body)
|
||||
recording = Recording.find(response_body['id'])
|
||||
post :stop, { :format => 'json', :id => recording.id }
|
||||
response.should be_success
|
||||
response_body = JSON.parse(response.body)
|
||||
response_body['id'].should_not be_nil
|
||||
Recording.find(response_body['id']).id.should == recording.id
|
||||
end
|
||||
|
||||
it "should not allow stop on a session not being recorded" do
|
||||
post :start, { :format => 'json', :music_session_id => @music_session.id }
|
||||
response_body = JSON.parse(response.body)
|
||||
recording = Recording.find(response_body['id'])
|
||||
post :stop, { :format => 'json', :id => recording.id }
|
||||
post :stop, { :format => 'json', :id => recording.id }
|
||||
response.status.should == 422
|
||||
response_body = JSON.parse(response.body)
|
||||
end
|
||||
|
||||
it "should not allow stop on a session requested by a different member" do
|
||||
|
||||
post :start, { :format => 'json', :music_session_id => @music_session.id }
|
||||
response_body = JSON.parse(response.body)
|
||||
recording = Recording.find(response_body['id'])
|
||||
user2 = FactoryGirl.create(:user)
|
||||
controller.current_user = user2
|
||||
post :stop, { :format => 'json', :id => recording.id }
|
||||
response.status.should == 403
|
||||
end
|
||||
end
|
||||
|
||||
describe "download track" do
|
||||
let(:mix) { FactoryGirl.create(:mix) }
|
||||
|
||||
it "should only allow a user to download a track if they have claimed the recording" do
|
||||
post :start, { :format => 'json', :music_session_id => @music_session.id }
|
||||
response_body = JSON.parse(response.body)
|
||||
recording = Recording.find(response_body['id'])
|
||||
post :stop, { :format => 'json', :id => recording.id }
|
||||
response.should be_success
|
||||
end
|
||||
|
||||
|
||||
it "is possible" do
|
||||
mix.touch
|
||||
recorded_track = mix.recording.recorded_tracks[0]
|
||||
controller.current_user = mix.recording.owner
|
||||
get :download, {id: recorded_track.recording.id, track_id: recorded_track.client_track_id}
|
||||
response.status.should == 302
|
||||
|
||||
recorded_track.reload
|
||||
recorded_track.download_count.should == 1
|
||||
|
||||
get :download, {id: recorded_track.recording.id, track_id: recorded_track.client_track_id}
|
||||
response.status.should == 302
|
||||
|
||||
recorded_track.reload
|
||||
recorded_track.download_count.should == 2
|
||||
end
|
||||
|
||||
|
||||
it "prevents download after limit is reached" do
|
||||
mix.touch
|
||||
recorded_track = mix.recording.recorded_tracks[0]
|
||||
recorded_track.download_count = APP_CONFIG.max_audio_downloads
|
||||
recorded_track.save!
|
||||
controller.current_user = recorded_track.user
|
||||
get :download, {format:'json', id: recorded_track.recording.id, track_id: recorded_track.client_track_id}
|
||||
response.status.should == 404
|
||||
JSON.parse(response.body, symbolize_names: true)[:message].should == "download limit surpassed"
|
||||
end
|
||||
|
||||
|
||||
it "lets admins surpass limit" do
|
||||
mix.touch
|
||||
recorded_track = mix.recording.recorded_tracks[0]
|
||||
recorded_track.download_count = APP_CONFIG.max_audio_downloads
|
||||
recorded_track.save!
|
||||
recorded_track.user.admin = true
|
||||
recorded_track.user.save!
|
||||
|
||||
controller.current_user = recorded_track.user
|
||||
get :download, {format:'json', id: recorded_track.recording.id, track_id: recorded_track.client_track_id}
|
||||
response.status.should == 302
|
||||
recorded_track.reload
|
||||
recorded_track.download_count.should == 101
|
||||
end
|
||||
end
|
||||
|
||||
describe "download backing track" do
|
||||
let(:mix) { FactoryGirl.create(:mix) }
|
||||
|
||||
it "should only allow a user to download a track if they have claimed the recording" do
|
||||
post :start, { :format => 'json', :music_session_id => @music_session.id }
|
||||
response_body = JSON.parse(response.body)
|
||||
recording = Recording.find(response_body['id'])
|
||||
post :stop, { :format => 'json', :id => recording.id }
|
||||
response.should be_success
|
||||
end
|
||||
|
||||
|
||||
it "is possible" do
|
||||
mix.touch
|
||||
recorded_track = mix.recording.recorded_tracks[0]
|
||||
controller.current_user = mix.recording.owner
|
||||
get :download, {id: recorded_track.recording.id, track_id: recorded_track.client_track_id}
|
||||
response.status.should == 302
|
||||
|
||||
recorded_track.reload
|
||||
recorded_track.download_count.should == 1
|
||||
|
||||
get :download, {id: recorded_track.recording.id, track_id: recorded_track.client_track_id}
|
||||
response.status.should == 302
|
||||
|
||||
recorded_track.reload
|
||||
recorded_track.download_count.should == 2
|
||||
end
|
||||
|
||||
|
||||
it "prevents download after limit is reached" do
|
||||
mix.touch
|
||||
recorded_track = mix.recording.recorded_tracks[0]
|
||||
recorded_track.download_count = APP_CONFIG.max_audio_downloads
|
||||
recorded_track.save!
|
||||
controller.current_user = recorded_track.user
|
||||
get :download, {format:'json', id: recorded_track.recording.id, track_id: recorded_track.client_track_id}
|
||||
response.status.should == 404
|
||||
JSON.parse(response.body, symbolize_names: true)[:message].should == "download limit surpassed"
|
||||
end
|
||||
|
||||
|
||||
it "lets admins surpass limit" do
|
||||
mix.touch
|
||||
recorded_track = mix.recording.recorded_tracks[0]
|
||||
recorded_track.download_count = APP_CONFIG.max_audio_downloads
|
||||
recorded_track.save!
|
||||
recorded_track.user.admin = true
|
||||
recorded_track.user.save!
|
||||
|
||||
controller.current_user = recorded_track.user
|
||||
get :download, {format:'json', id: recorded_track.recording.id, track_id: recorded_track.client_track_id}
|
||||
response.status.should == 302
|
||||
recorded_track.reload
|
||||
recorded_track.download_count.should == 101
|
||||
describe "start" do
|
||||
it "should work" do
|
||||
post :start, {:format => 'json', :music_session_id => @music_session.id}
|
||||
response.should be_success
|
||||
response_body = JSON.parse(response.body)
|
||||
response_body['id'].should_not be_nil
|
||||
recording = Recording.find(response_body['id'])
|
||||
recorded_jam_track_track = response_body["recorded_jam_track_tracks"][0]
|
||||
recorded_jam_track_track["id"].should eq(@jam_track.jam_track_tracks[0].id)
|
||||
recorded_jam_track_track["timeline"].should eq([])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -1,16 +1,310 @@
|
|||
describe "DownloadJamTrack", ->
|
||||
|
||||
beforeEach ->
|
||||
this.fixtures = fixture.load("downoadJamTrack.html", "user_sync_track1.json"); # append these fixtures which were already cached
|
||||
this.server = sinon.fakeServer.create();
|
||||
this.fixtures = fixture.load("downloadJamTrack.html"); # append these fixtures which were already cached
|
||||
window.jamClient = sinon.stub()
|
||||
this.downloadJamTrack = new JK.DownloadJamTrack()
|
||||
this.downloadJamTrack.init()
|
||||
$('body').append(this.downloadJamTrack.root)
|
||||
this.app = sinon.stub()
|
||||
this.jamTrackId = '1'
|
||||
this.jamTrack = {id: this.jamTrackId, jam_track_right_id: '1', name: 'Back in Black', version:'1'}
|
||||
window.gon = {}
|
||||
window.JK.JamServer = {}
|
||||
window.stats = {}
|
||||
@statsSpy = window.stats.write = sinon.spy()
|
||||
window.JK.JamServer.send = sinon.stub(); # attempts to subscribe to the socket will need this
|
||||
|
||||
afterEach ->
|
||||
this.server.restore();
|
||||
window.stats.write.reset()
|
||||
|
||||
describe "normal browser", ->
|
||||
|
||||
beforeEach ->
|
||||
window.gon.isNativeClient = false
|
||||
@showNoClientSpy = sinon.spy(JK.DownloadJamTrack.prototype, 'showNoClient')
|
||||
@downloadJamTrack = new JK.DownloadJamTrack(@app, @jamTrack)
|
||||
$('body').append(this.downloadJamTrack.root)
|
||||
|
||||
afterEach ->
|
||||
@showNoClientSpy.restore()
|
||||
|
||||
it "switches to 'no client' correctly", ->
|
||||
window.jamClient.JamTrackGetTrackDetail = sinon.stub()
|
||||
window.jamClient.InvalidateJamTrack = sinon.stub()
|
||||
#window.jamClient.JamTrackGetTrackDetail.returns({'key_state' : 'ready'})
|
||||
|
||||
@downloadJamTrack.init();
|
||||
|
||||
expect(window.jamClient.JamTrackGetTrackDetail.callCount).toBe(0)
|
||||
expect(@showNoClientSpy.calledOnce).toBe(true)
|
||||
expect(@downloadJamTrack.stateHolder.find('.state-no-client')).toHaveLength(1)
|
||||
expect(@statsSpy.calledOnce).toBe(true)
|
||||
|
||||
describe "client", ->
|
||||
|
||||
beforeEach ->
|
||||
window.gon.isNativeClient = true
|
||||
|
||||
describe "already synchronized", ->
|
||||
beforeEach ->
|
||||
@showSynchronizedSpy = sinon.spy(JK.DownloadJamTrack.prototype, 'showSynchronized')
|
||||
@downloadJamTrack = new JK.DownloadJamTrack(@app, @jamTrack)
|
||||
$('body').append(@downloadJamTrack.root)
|
||||
|
||||
afterEach ->
|
||||
@showSynchronizedSpy.restore()
|
||||
@downloadJamTrack.destroy()
|
||||
|
||||
it "shows synchronized state", ->
|
||||
window.jamClient.JamTrackGetTrackDetail = sinon.stub()
|
||||
window.jamClient.JamTrackGetTrackDetail.returns({'key_state' : 'ready', 'version' : '1'})
|
||||
window.jamClient.InvalidateJamTrack = sinon.stub()
|
||||
|
||||
@downloadJamTrack.init();
|
||||
|
||||
expect(window.jamClient.JamTrackGetTrackDetail.callCount).toBe(1)
|
||||
expect(window.jamClient.InvalidateJamTrack.callCount).toBe(0)
|
||||
expect(@showSynchronizedSpy.calledOnce).toBe(true)
|
||||
expect(@downloadJamTrack.transitionTimer).toBe(null)
|
||||
expect(@downloadJamTrack.downloadTimer).toBe(null)
|
||||
expect(@statsSpy.calledOnce).toBe(true)
|
||||
|
||||
expect(@downloadJamTrack.stateHolder.find('.state-synchronized')).toHaveLength(1)
|
||||
|
||||
describe "pending", ->
|
||||
beforeEach ->
|
||||
window.jamClient.JamTrackKeysRequest = sinon.stub()
|
||||
@showSynchronizedSpy = sinon.spy(JK.DownloadJamTrack.prototype, 'showSynchronized')
|
||||
@showErrorSpy = sinon.spy(JK.DownloadJamTrack.prototype, 'showError')
|
||||
@showKeyingSpy = sinon.spy(JK.DownloadJamTrack.prototype, 'showKeying')
|
||||
@downloadJamTrack = new JK.DownloadJamTrack(@app, @jamTrack)
|
||||
@downloadJamTrack.states.keying.max_time = -1 # hurry up the test, instead of waiting 10 seconds
|
||||
$('body').append(@downloadJamTrack.root)
|
||||
|
||||
afterEach ->
|
||||
@showSynchronizedSpy.restore()
|
||||
@showErrorSpy.restore()
|
||||
@showKeyingSpy.restore()
|
||||
@downloadJamTrack.destroy()
|
||||
|
||||
it "shows errored state due to timeout", ->
|
||||
window.jamClient.JamTrackGetTrackDetail = sinon.stub()
|
||||
window.jamClient.JamTrackGetTrackDetail.returns({'key_state' : 'pending', 'version' : '1'})
|
||||
window.jamClient.InvalidateJamTrack = sinon.stub()
|
||||
|
||||
@downloadJamTrack.init();
|
||||
|
||||
expect(window.jamClient.JamTrackGetTrackDetail.callCount).toBe(1)
|
||||
expect(@showKeyingSpy.calledOnce).toBe(true)
|
||||
expect(@downloadJamTrack.states.keying.timer).toNotBe(null)
|
||||
|
||||
@downloadJamTrack.stateIntervalCheck()
|
||||
|
||||
expect(window.jamClient.JamTrackGetTrackDetail.callCount).toBe(2)
|
||||
|
||||
expect(@showErrorSpy.calledOnce).toBe(true)
|
||||
expect(@downloadJamTrack.states.keying.timer).toBe(null)
|
||||
expect(@downloadJamTrack.stateHolder.find('.state-errored')).toHaveLength(1)
|
||||
expect(@downloadJamTrack.stateHolder.find('.state-errored .msg')).toContainText('It took too long for the JamTrack to be keyed.')
|
||||
expect(@statsSpy.calledOnce).toBe(true)
|
||||
expect(@downloadJamTrack.attempts).toBe(1)
|
||||
|
||||
# now simulate a retry attempt
|
||||
@downloadJamTrack.stateHolder.find('.retry-button').trigger('click')
|
||||
|
||||
# and verify that we are beginning a re-attempt
|
||||
expect(window.jamClient.JamTrackGetTrackDetail.callCount).toBe(3)
|
||||
expect(@showKeyingSpy.calledTwice).toBe(true)
|
||||
expect(@downloadJamTrack.states.keying.timer).toNotBe(null)
|
||||
expect(@downloadJamTrack.attempts).toBe(2)
|
||||
|
||||
|
||||
it "shows synchronized", ->
|
||||
window.jamClient.JamTrackGetTrackDetail = sinon.stub()
|
||||
window.jamClient.JamTrackGetTrackDetail.returns({'key_state' : 'pending', 'version' : '1'})
|
||||
window.jamClient.InvalidateJamTrack = sinon.stub()
|
||||
|
||||
@downloadJamTrack.init()
|
||||
|
||||
expect(window.jamClient.JamTrackGetTrackDetail.callCount).toBe(1)
|
||||
expect(@showKeyingSpy.calledOnce).toBe(true)
|
||||
|
||||
# keying timer should be firing
|
||||
expect(@downloadJamTrack.states.keying.timer).toNotBe(null)
|
||||
|
||||
# say the keys have been fetched
|
||||
window.jamClient.JamTrackGetTrackDetail.returns({'key_state' : 'ready', 'version' : '1'})
|
||||
window.jamClient.InvalidateJamTrack = sinon.stub()
|
||||
|
||||
# then do a check
|
||||
@downloadJamTrack.stateIntervalCheck()
|
||||
|
||||
expect(@showSynchronizedSpy.calledOnce).toBe(true)
|
||||
expect(@downloadJamTrack.states.keying.timer).toBe(null)
|
||||
expect(@downloadJamTrack.stateHolder.find('.state-synchronized')).toHaveLength(1)
|
||||
expect(@statsSpy.calledOnce).toBe(true)
|
||||
|
||||
|
||||
|
||||
describe "JamTrack needs downloading", ->
|
||||
beforeEach ->
|
||||
window.jamClient.JamTrackDownload = sinon.stub()
|
||||
@showSynchronizedSpy = sinon.spy(JK.DownloadJamTrack.prototype, 'showSynchronized')
|
||||
@showErrorSpy = sinon.spy(JK.DownloadJamTrack.prototype, 'showError')
|
||||
@showKeyingSpy = sinon.spy(JK.DownloadJamTrack.prototype, 'showKeying')
|
||||
@showDownloadingSpy = sinon.spy(JK.DownloadJamTrack.prototype, 'showDownloading')
|
||||
@showPackagingSpy = sinon.spy(JK.DownloadJamTrack.prototype, 'showPackaging')
|
||||
@downloadJamTrack = new JK.DownloadJamTrack(@app, @jamTrack)
|
||||
@downloadJamTrack.states.keying.max_time = -1 # hurry up the test, instead of waiting 10 seconds
|
||||
$('body').append(@downloadJamTrack.root)
|
||||
|
||||
afterEach ->
|
||||
@showSynchronizedSpy.restore()
|
||||
@showErrorSpy.restore()
|
||||
@showKeyingSpy.restore()
|
||||
@showDownloadingSpy.restore()
|
||||
@showPackagingSpy.restore()
|
||||
@downloadJamTrack.destroy()
|
||||
|
||||
it "shows downloading for signed package", ->
|
||||
window.jamClient.JamTrackKeysRequest = sinon.stub()
|
||||
window.jamClient.JamTrackGetTrackDetail = sinon.stub()
|
||||
window.jamClient.JamTrackGetTrackDetail.returns({'key_state' : 'unknown', 'version' : '1'})
|
||||
window.jamClient.InvalidateJamTrack = sinon.stub()
|
||||
|
||||
spyOn(@downloadJamTrack.rest, 'getJamTrackRight').andCallFake((data) =>
|
||||
d = $.Deferred();
|
||||
d.resolve({signing_state: 'SIGNED'});
|
||||
d.promise();
|
||||
)
|
||||
|
||||
window.jamClient.JamTrackDownload = sinon.stub()
|
||||
|
||||
@downloadJamTrack.init()
|
||||
|
||||
expect(window.jamClient.JamTrackGetTrackDetail.callCount).toBe(1)
|
||||
expect(window.jamClient.JamTrackDownload.callCount).toBe(1)
|
||||
expect(@showDownloadingSpy.calledOnce).toBe(true)
|
||||
expect(@downloadJamTrack.stateHolder.find('.state-downloading')).toHaveLength(1)
|
||||
|
||||
eval(@downloadJamTrack.makeDownloadSuccessCallback() + '()')
|
||||
|
||||
expect(@showKeyingSpy.calledOnce).toBe(true)
|
||||
expect(@downloadJamTrack.stateHolder.find('.state-keying')).toHaveLength(1)
|
||||
|
||||
# keying timer should be firing
|
||||
expect(@downloadJamTrack.states.keying.timer).toNotBe(null)
|
||||
|
||||
# say the keys have been fetched
|
||||
window.jamClient.JamTrackGetTrackDetail.returns({'key_state' : 'ready', 'version' : '1'})
|
||||
window.jamClient.InvalidateJamTrack = sinon.stub()
|
||||
|
||||
# check state again
|
||||
@downloadJamTrack.stateIntervalCheck()
|
||||
|
||||
# we should now be synchronized
|
||||
expect(@showSynchronizedSpy.calledOnce).toBe(true)
|
||||
expect(@downloadJamTrack.states.keying.timer).toBe(null)
|
||||
expect(@downloadJamTrack.stateHolder.find('.state-synchronized')).toHaveLength(1)
|
||||
expect(@statsSpy.calledOnce).toBe(true)
|
||||
|
||||
it "is not yet packaged", ->
|
||||
window.jamClient.JamTrackGetTrackDetail = sinon.stub()
|
||||
window.jamClient.JamTrackGetTrackDetail.returns({'key_state' : 'unknown', 'version' : '1'})
|
||||
window.jamClient.InvalidateJamTrack = sinon.stub()
|
||||
|
||||
spyOn(@downloadJamTrack.rest, 'getJamTrackRight').andCallFake((data) =>
|
||||
d = $.Deferred();
|
||||
d.resolve({signing_state: 'QUIET'});
|
||||
d.promise();
|
||||
)
|
||||
|
||||
spyOn(@downloadJamTrack.rest, 'enqueueJamTrack').andCallFake((data) =>
|
||||
d = $.Deferred();
|
||||
d.resolve({});
|
||||
d.promise();
|
||||
)
|
||||
|
||||
window.jamClient.JamTrackDownload = sinon.stub()
|
||||
|
||||
@downloadJamTrack.init()
|
||||
|
||||
expect(@downloadJamTrack.attemptedEnqueue).toBe(true)
|
||||
expect(@downloadJamTrack.transitionTimer?).toBe(true)
|
||||
|
||||
# simulate poke from server saying the track has been queued
|
||||
@downloadJamTrack.onJamTrackRightEvent(null, {body: {signing_state: 'QUEUED'}})
|
||||
|
||||
# the frontend should be saying that it's packaging now
|
||||
expect(@downloadJamTrack.transitionTimer?).toBe(true)
|
||||
expect(@showPackagingSpy.calledOnce).toBe(true)
|
||||
expect(@downloadJamTrack.stateHolder.find('.state-packaging')).toHaveLength(1)
|
||||
|
||||
# simulate poke from server saying the track is currently signing
|
||||
@downloadJamTrack.onJamTrackRightEvent(null, {body: {signing_state: 'SIGNING'}})
|
||||
|
||||
# the frontend still be saying it's packaging
|
||||
expect(@downloadJamTrack.transitionTimer?).toBe(true)
|
||||
expect(@showPackagingSpy.calledOnce).toBe(true)
|
||||
|
||||
# simulate poke from server saying the track is signed
|
||||
@downloadJamTrack.onJamTrackRightEvent(null, {body: {signing_state: 'SIGNED'}})
|
||||
|
||||
expect(@downloadJamTrack.transitionTimer?).toBe(false)
|
||||
|
||||
# downloading has started; other test covers this, so we stop testing
|
||||
expect(@showDownloadingSpy.calledOnce).toBe(true)
|
||||
expect(@downloadJamTrack.stateHolder.find('.state-downloading')).toHaveLength(1)
|
||||
|
||||
# since we haven't yet made it to a leave node, make sure we haven't reported a stat
|
||||
expect(@statsSpy.callCount).toBe(0)
|
||||
|
||||
it "queue time out when packaging", ->
|
||||
window.jamClient.JamTrackGetTrackDetail = sinon.stub()
|
||||
window.jamClient.JamTrackGetTrackDetail.returns({'key_state' : 'unknown', 'version' : '1'})
|
||||
window.jamClient.InvalidateJamTrack = sinon.stub()
|
||||
|
||||
getJamTrackRightSpy = spyOn(@downloadJamTrack.rest, 'getJamTrackRight')
|
||||
getJamTrackRightSpy.andCallFake((data) =>
|
||||
d = $.Deferred();
|
||||
d.resolve({signing_state: 'QUIET'});
|
||||
d.promise();
|
||||
)
|
||||
|
||||
spyOn(@downloadJamTrack.rest, 'enqueueJamTrack').andCallFake((data) =>
|
||||
d = $.Deferred();
|
||||
d.resolve({});
|
||||
d.promise();
|
||||
)
|
||||
|
||||
window.jamClient.JamTrackDownload = sinon.stub()
|
||||
|
||||
@downloadJamTrack.init()
|
||||
|
||||
expect(@downloadJamTrack.attemptedEnqueue).toBe(true)
|
||||
expect(@downloadJamTrack.transitionTimer?).toBe(true)
|
||||
|
||||
getJamTrackRightSpy.reset()
|
||||
|
||||
# simulate timer running out, and server check resulting in QUEUED_TIMEOUT
|
||||
getJamTrackRightSpy.andCallFake((data) =>
|
||||
d = $.Deferred();
|
||||
d.resolve({signing_state: 'QUEUED_TIMEOUT'});
|
||||
d.promise();
|
||||
)
|
||||
|
||||
@downloadJamTrack.transitionCheck()
|
||||
|
||||
# the frontend should be saying that it's packaging now
|
||||
expect(@downloadJamTrack.transitionTimer?).toBe(false)
|
||||
expect(@showErrorSpy.calledOnce).toBe(true)
|
||||
expect(@downloadJamTrack.stateHolder.find('.state-errored')).toHaveLength(1)
|
||||
expect(@downloadJamTrack.stateHolder.find('.state-errored .msg')).toContainText('The server took too long to begin processing your JamTrack.')
|
||||
|
||||
expect(@statsSpy.calledOnce).toBe(true)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
it "display state correctly", ->
|
||||
$track = this.syncViewer.createTrack(this.track1)
|
||||
this.syncViewer.updateTrackState($track)
|
||||
|
|
|
|||
Loading…
Reference in New Issue