VRFS-2795 merging with feature/musician_profile_enhancements
|
|
@ -41,7 +41,7 @@ gem 'uuidtools', '2.1.2'
|
|||
gem 'jquery-rails' # , '2.3.0' # pinned because jquery-ui-rails was split from jquery-rails, but activeadmin doesn't support this gem yet
|
||||
gem 'jquery-ui-rails', '4.2.1'
|
||||
gem 'rails3-jquery-autocomplete'
|
||||
gem 'activeadmin', '0.6.2'
|
||||
gem 'activeadmin' #, github: 'activeadmin', branch: '0-6-stable'
|
||||
gem 'mime-types', '1.25'
|
||||
gem 'meta_search'
|
||||
gem 'fog', "~> 1.18.0"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,71 @@
|
|||
ActiveAdmin.register Cohort, :as => 'Cohorts' do
|
||||
|
||||
menu :label => 'Cohorts All-time', :parent => 'Reports'
|
||||
|
||||
config.sort_order = 'group_start_desc'
|
||||
config.batch_actions = false
|
||||
config.clear_action_items!
|
||||
config.filters = false
|
||||
config.per_page = 50
|
||||
|
||||
controller do
|
||||
|
||||
def scoped_collection
|
||||
objs = super
|
||||
Cohort.alltime_cohorts!
|
||||
objs.where(all_time: true).order('group_start DESC')
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
index :title => "All-Time Cohorts" do
|
||||
column 'Cohort' do |cc|
|
||||
div(class: :cohort_col) { cc.group_start_str }
|
||||
end
|
||||
|
||||
column Cohort::ALLTIME_LABELS[:registered_users] do |cc|
|
||||
div(class: :cohort_col) { cc.data_val(:registered_users) }
|
||||
end
|
||||
|
||||
column Cohort::ALLTIME_LABELS[:first_downloaded_client_at] do |cc|
|
||||
div(class: :cohort_col) { cc.data_val(:first_downloaded_client_at) }
|
||||
end
|
||||
column '%' do |cc| div(class: :cohort_col) { cc.data_val(:first_downloaded_client_at, true) } end
|
||||
|
||||
column Cohort::ALLTIME_LABELS[:first_certified_gear_at] do |cc|
|
||||
div(class: :cohort_col) { cc.data_val(:first_certified_gear_at) }
|
||||
end
|
||||
column '%' do |cc| div(class: :cohort_col) { cc.data_val(:first_certified_gear_at, true) } end
|
||||
|
||||
column Cohort::ALLTIME_LABELS[:music_sessions_user_history] do |cc|
|
||||
div(class: :cohort_col) { cc.data_val(:music_sessions_user_history) }
|
||||
end
|
||||
column '%' do |cc| div(class: :cohort_col) { cc.data_val(:music_sessions_user_history, true) } end
|
||||
|
||||
column Cohort::ALLTIME_LABELS[:jam_tracks_played] do |cc|
|
||||
div(class: :cohort_col) { cc.data_val(:jam_tracks_played) }
|
||||
end
|
||||
column '%' do |cc| div(class: :cohort_col) { cc.data_val(:jam_tracks_played, true) } end
|
||||
|
||||
column Cohort::ALLTIME_LABELS[:jam_track_rights] do |cc|
|
||||
div(class: :cohort_col) { cc.data_val(:jam_track_rights) }
|
||||
end
|
||||
column '%' do |cc| div(class: :cohort_col) { cc.data_val(:jam_track_rights, true) } end
|
||||
|
||||
column Cohort::ALLTIME_LABELS[:recorded_tracks] do |cc|
|
||||
div(class: :cohort_col) { cc.data_val(:recorded_tracks) }
|
||||
end
|
||||
column '%' do |cc| div(class: :cohort_col) { cc.data_val(:recorded_tracks, true) } end
|
||||
|
||||
column Cohort::ALLTIME_LABELS[:friendships] do |cc|
|
||||
div(class: :cohort_col) { cc.data_val(:friendships) }
|
||||
end
|
||||
column '%' do |cc| div(class: :cohort_col) { cc.data_val(:friendships, true) } end
|
||||
|
||||
column Cohort::ALLTIME_LABELS[:invited_users] do |cc|
|
||||
div(class: :cohort_col) { cc.data_val(:invited_users) }
|
||||
end
|
||||
column '%' do |cc| div(class: :cohort_col) { cc.data_val(:invited_users, true) } end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
ActiveAdmin.register Cohort, :as => 'Cohorts Monthly' do
|
||||
|
||||
menu :label => 'Cohorts Monthly', :parent => 'Reports'
|
||||
|
||||
config.sort_order = 'group_start_desc'
|
||||
config.batch_actions = false
|
||||
config.clear_action_items!
|
||||
config.per_page = 50
|
||||
|
||||
filter(:monthly_start, as: :select, collection: Cohort.monthly_starts)
|
||||
|
||||
controller do
|
||||
def scoped_collection
|
||||
args = params[:q] || {}
|
||||
Cohort.monthly_cohorts!(Time.parse(args[:monthly_start_eq])) if ! args[:monthly_start_eq].nil?
|
||||
super.where(all_time: false).order('group_start DESC')
|
||||
end
|
||||
end
|
||||
|
||||
index :title => proc { "Monthly Cohorts #{params[:q] ? '('+Time.parse(params[:q][:monthly_start_eq]).strftime('%Y-%m')+')' : ''}" } do
|
||||
|
||||
column 'Cohort' do |cc|
|
||||
div(class: :cohort_col) { cc.group_start_str }
|
||||
end
|
||||
|
||||
column Cohort::MONTHLY_LABELS[:registered_users] do |cc|
|
||||
div(class: :cohort_col) { cc.data_val(:registered_users) }
|
||||
end
|
||||
|
||||
column Cohort::MONTHLY_LABELS[:first_downloaded_client_at] do |cc|
|
||||
div(class: :cohort_col) { cc.data_val(:first_downloaded_client_at) }
|
||||
end
|
||||
column '%' do |cc| div(class: :cohort_col) { cc.data_val(:first_downloaded_client_at, true) } end
|
||||
|
||||
column Cohort::MONTHLY_LABELS[:first_certified_gear_at] do |cc|
|
||||
div(class: :cohort_col) { cc.data_val(:first_certified_gear_at) }
|
||||
end
|
||||
column '%' do |cc| div(class: :cohort_col) { cc.data_val(:first_certified_gear_at, true) } end
|
||||
|
||||
column Cohort::MONTHLY_LABELS[:music_sessions_user_history_1] do |cc|
|
||||
div(class: :cohort_col) { cc.data_val(:music_sessions_user_history_1) }
|
||||
end
|
||||
column '%' do |cc| div(class: :cohort_col) { cc.data_val(:music_sessions_user_history_1, true) } end
|
||||
|
||||
column Cohort::MONTHLY_LABELS[:music_sessions_user_history_2_5] do |cc|
|
||||
div(class: :cohort_col) { cc.data_val(:music_sessions_user_history_2_5) }
|
||||
end
|
||||
column '%' do |cc| div(class: :cohort_col) { cc.data_val(:music_sessions_user_history_2_5, true) } end
|
||||
|
||||
column Cohort::MONTHLY_LABELS[:music_sessions_user_history_6_] do |cc|
|
||||
div(class: :cohort_col) { cc.data_val(:music_sessions_user_history_6_) }
|
||||
end
|
||||
column '%' do |cc| div(class: :cohort_col) { cc.data_val(:music_sessions_user_history_6_, true) } end
|
||||
|
||||
column Cohort::MONTHLY_LABELS[:jam_tracks_played_1] do |cc|
|
||||
div(class: :cohort_col) { cc.data_val(:jam_tracks_played_1) }
|
||||
end
|
||||
column '%' do |cc| div(class: :cohort_col) { cc.data_val(:jam_tracks_played_1, true) } end
|
||||
|
||||
column Cohort::MONTHLY_LABELS[:jam_tracks_played_2_5] do |cc|
|
||||
div(class: :cohort_col) { cc.data_val(:jam_tracks_played_2_5) }
|
||||
end
|
||||
column '%' do |cc| div(class: :cohort_col) { cc.data_val(:jam_tracks_played_2_5, true) } end
|
||||
|
||||
column Cohort::MONTHLY_LABELS[:jam_tracks_played_6_] do |cc|
|
||||
div(class: :cohort_col) { cc.data_val(:jam_tracks_played_6_) }
|
||||
end
|
||||
column '%' do |cc| div(class: :cohort_col) { cc.data_val(:jam_tracks_played_6_, true) } end
|
||||
|
||||
column Cohort::MONTHLY_LABELS[:jam_track_rights_redeemed] do |cc|
|
||||
div(class: :cohort_col) { cc.data_val(:jam_track_rights_redeemed) }
|
||||
end
|
||||
column '%' do |cc| div(class: :cohort_col) { cc.data_val(:jam_track_rights_redeemed, true) } end
|
||||
|
||||
column Cohort::MONTHLY_LABELS[:jam_track_rights] do |cc|
|
||||
div(class: :cohort_col) { cc.data_val(:jam_track_rights) }
|
||||
end
|
||||
column '%' do |cc| div(class: :cohort_col) { cc.data_val(:jam_track_rights, true) } end
|
||||
|
||||
column Cohort::MONTHLY_LABELS[:recorded_tracks] do |cc|
|
||||
div(class: :cohort_col) { cc.data_val(:recorded_tracks) }
|
||||
end
|
||||
column '%' do |cc| div(class: :cohort_col) { cc.data_val(:recorded_tracks, true) } end
|
||||
|
||||
column Cohort::MONTHLY_LABELS[:friendships] do |cc|
|
||||
div(class: :cohort_col) { cc.data_val(:friendships) }
|
||||
end
|
||||
column '%' do |cc| div(class: :cohort_col) { cc.data_val(:friendships, true) } end
|
||||
|
||||
column Cohort::MONTHLY_LABELS[:invited_users] do |cc|
|
||||
div(class: :cohort_col) { cc.data_val(:invited_users) }
|
||||
end
|
||||
column '%' do |cc| div(class: :cohort_col) { cc.data_val(:invited_users, true) } end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -3,7 +3,7 @@ ActiveAdmin.register JamRuby::CrashDump, :as => 'Crash Dump' do
|
|||
filter :timestamp
|
||||
filter :user_email, :as => :string
|
||||
filter :client_id
|
||||
menu :parent => 'Debug'
|
||||
menu :parent => 'Misc'
|
||||
|
||||
index do
|
||||
column "Timestamp" do |post|
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
ActiveAdmin.register JamRuby::EmailBatch, :as => 'Batch Emails' do
|
||||
|
||||
menu :label => 'Batch Emails', :parent => 'Email'
|
||||
menu :label => 'Batch Emails', :parent => 'Misc'
|
||||
|
||||
config.sort_order = 'updated_at DESC'
|
||||
config.batch_actions = false
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
ActiveAdmin.register JamRuby::EmailBatchScheduledSessions, :as => 'Daily Sessions' do
|
||||
|
||||
menu :label => 'Daily Sessions', :parent => 'Email'
|
||||
menu :label => 'Daily Sessions', :parent => 'Misc'
|
||||
|
||||
config.sort_order = 'updated_at DESC'
|
||||
config.filters = false
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
ActiveAdmin.register JamRuby::Event, :as => 'Event' do
|
||||
menu :parent => 'Events'
|
||||
menu :parent => 'Misc'
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
ActiveAdmin.register JamRuby::EventSession, :as => 'Event Session' do
|
||||
menu :parent => 'Events'
|
||||
menu :parent => 'Misc'
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,54 @@
|
|||
ActiveAdmin.register_page "Fake Purchaser" do
|
||||
menu :parent => 'Misc'
|
||||
|
||||
|
||||
page_action :bulk_jamtrack_purchase, :method => :post do
|
||||
|
||||
puts params.inspect
|
||||
|
||||
user_field = params[:jam_ruby_jam_track_right][:user]
|
||||
|
||||
if user_field.blank?
|
||||
redirect_to admin_fake_purchaser_path, :notice => "user not specified"
|
||||
return
|
||||
end
|
||||
|
||||
bits = user_field.strip.split(' ')
|
||||
|
||||
user = User.find_by_email(bits[0])
|
||||
if user.nil?
|
||||
redirect_to admin_fake_purchaser_path, :notice =>"no user with email #{bits[0]}"
|
||||
return
|
||||
end
|
||||
|
||||
if !user.admin
|
||||
redirect_to admin_fake_purchaser_path, :notice =>"user is not admin"
|
||||
return
|
||||
end
|
||||
|
||||
count = 0
|
||||
JamTrack.all.each do |jam_track|
|
||||
unless jam_track.right_for_user(user)
|
||||
|
||||
jam_track_right=JamTrackRight.new
|
||||
jam_track_right.user = user
|
||||
jam_track_right.jam_track = jam_track
|
||||
jam_track_right.is_test_purchase = true
|
||||
jam_track_right.save!
|
||||
count = count + 1
|
||||
end
|
||||
end
|
||||
|
||||
redirect_to admin_fake_purchaser_path, :notice => "Bought #{count} jamtracks for #{user.email}"
|
||||
end
|
||||
|
||||
content do
|
||||
|
||||
semantic_form_for JamTrackRight.new, :url => admin_fake_purchaser_bulk_jamtrack_purchase_path, :builder => ActiveAdmin::FormBuilder do |f|
|
||||
f.inputs "Admin User to Fake JamTrack Purchases" do
|
||||
f.input :user, :as => :autocomplete, :url => autocomplete_user_email_admin_users_path, :input_html => { :id_element => "#jam_trak_right_user_id" }, hint: 'All JamTracks in the system will be \'bought\' for this user. No Recurly interaction occurs with this feature.'
|
||||
end
|
||||
f.actions
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -2,6 +2,6 @@ ActiveAdmin.register JamRuby::IspScoreBatch, :as => 'Isp Score Data' do
|
|||
|
||||
config.sort_order = 'created_at_desc'
|
||||
|
||||
menu :parent => 'Debug'
|
||||
menu :parent => 'Misc'
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
ActiveAdmin.register JamRuby::ArtifactUpdate, :as => 'Artifacts' do
|
||||
menu :label => 'Artifacts'
|
||||
menu :label => 'Artifacts', :parent => 'Operations'
|
||||
|
||||
config.sort_order = 'product,environment'
|
||||
#config.batch_actions = false
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@ ActiveAdmin.register JamRuby::User, :as => 'Users' do
|
|||
User.select("email, first_name, last_name, id").where(["email ILIKE ? OR first_name ILIKE ? OR last_name ILIKE ?", "%#{parameters[:term]}%", "%#{parameters[:term]}%", "%#{parameters[:term]}%"])
|
||||
end
|
||||
|
||||
|
||||
def create
|
||||
@jam_ruby_user = JamRuby::User.new(params[:jam_ruby_user])
|
||||
@jam_ruby_user.administratively_created = true
|
||||
|
|
|
|||
|
|
@ -22,29 +22,18 @@ ActiveAdmin.register JamRuby::JamTrack, :as => 'JamTracks' do
|
|||
links
|
||||
end
|
||||
|
||||
|
||||
column :id
|
||||
column :name
|
||||
column :description
|
||||
column :version
|
||||
column :time_signature
|
||||
column :status
|
||||
column :recording_type
|
||||
column :original_artist
|
||||
column :songwriter
|
||||
column :publisher
|
||||
column :name
|
||||
column :status
|
||||
column :master_track do |jam_track| jam_track.master_track.nil? ? 'None' : (link_to "Download", jam_track.master_track.url_by_sample_rate(44)) end
|
||||
column :licensor
|
||||
column :pro
|
||||
column :genre
|
||||
column :sales_region
|
||||
column :price
|
||||
column :reproduction_royalty
|
||||
column :public_performance_royalty
|
||||
column :reproduction_royalty_amount
|
||||
column :licensor_royalty_amount
|
||||
column :pro_royalty_amount
|
||||
column :url
|
||||
column :created_at
|
||||
column :id
|
||||
|
||||
column :jam_track_tracks do |jam_track|
|
||||
table_for jam_track.jam_track_tracks.order('position ASC') do
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
ActiveAdmin.register JamRuby::PromoBuzz, :as => 'Buzz' do
|
||||
|
||||
menu :label => 'Buzz', :parent => 'Home Page'
|
||||
menu :label => 'Promo Buzz', :parent => 'Misc'
|
||||
|
||||
config.sort_order = 'position ASC aasm_state DESC updated_at DESC'
|
||||
config.batch_actions = false
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
ActiveAdmin.register JamRuby::PromoLatest, :as => 'Latest' do
|
||||
|
||||
menu :label => 'Latest', :parent => 'Home Page'
|
||||
menu :label => 'Promo Latest', :parent => 'Misc'
|
||||
|
||||
config.batch_actions = false
|
||||
config.sort_order = ''
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
ActiveAdmin.register_page "Download CSV" do
|
||||
menu :parent => 'Score'
|
||||
=begin
|
||||
ActiveAdmin.register_page "Download Score CSV" do
|
||||
menu :parent => 'Misc'
|
||||
|
||||
page_action :create_csv, :method => :post do
|
||||
|
||||
|
|
@ -95,4 +96,5 @@ ActiveAdmin.register_page "Download CSV" do
|
|||
#end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
=end
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
=begin
|
||||
ActiveAdmin.register JamRuby::ScoreHistory, :as => 'Score History' do
|
||||
menu :parent => 'Score'
|
||||
|
||||
|
|
@ -80,3 +81,4 @@ ActiveAdmin.register JamRuby::ScoreHistory, :as => 'Score History' do
|
|||
column "To Client", :to_client_id
|
||||
end
|
||||
end
|
||||
=end
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
ActiveAdmin.register_page "Current Scoring Load" do
|
||||
menu :parent => 'Score'
|
||||
menu :parent => 'Misc'
|
||||
|
||||
content :title => "Current Scoring Load" do
|
||||
table_for GetWork.summary do
|
||||
|
|
|
|||
|
|
@ -31,3 +31,7 @@
|
|||
// .active_admin applies to any Active Admin namespace
|
||||
// .admin_namespace applies to the admin namespace (eg: /admin)
|
||||
// .other_namespace applies to a custom namespace named other (eg: /other)
|
||||
|
||||
.cohort_col {
|
||||
text-align: center;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,362 @@
|
|||
require 'date'
|
||||
|
||||
class Cohort < ActiveRecord::Base
|
||||
|
||||
EARLIEST_DATE = Time.parse('2014-03-01')
|
||||
TOTAL_COHORT_DATE = Time.at(0)
|
||||
|
||||
ALLTIME_LABELS = {
|
||||
registered_users: 'Registered Users',
|
||||
first_downloaded_client_at: 'DL app',
|
||||
first_certified_gear_at: 'Certified Gear',
|
||||
music_sessions_user_history: 'Played Online',
|
||||
jam_tracks_played: 'Played JT',
|
||||
jam_track_rights: 'Purchased JT',
|
||||
recorded_tracks: 'Made Recording',
|
||||
friendships: 'Friended',
|
||||
invited_users: 'Invite Others',
|
||||
}
|
||||
|
||||
MONTHLY_LABELS = {
|
||||
registered_users: 'Registered Users',
|
||||
first_downloaded_client_at: 'DL app',
|
||||
first_certified_gear_at: 'Certified Gear',
|
||||
music_sessions_user_history_1: 'Played Online 1',
|
||||
music_sessions_user_history_2_5: 'Played Online 2-5',
|
||||
music_sessions_user_history_6_: 'Played Online 6+',
|
||||
jam_tracks_played_1: 'Played JT 1',
|
||||
jam_tracks_played_2_5: 'Played JT 2-5',
|
||||
jam_tracks_played_6_: 'Played JT 6+',
|
||||
jam_track_rights_redeemed: 'Redeemed JT',
|
||||
jam_track_rights: 'Purchased JT',
|
||||
recorded_tracks: 'Made Recording',
|
||||
friendships: 'Friended',
|
||||
invited_users: 'Invite Others',
|
||||
}
|
||||
|
||||
attr_accessible :all_time, :monthly_start
|
||||
serialize :data_set, JSON
|
||||
|
||||
before_create do
|
||||
self.data_set ||= {}
|
||||
end
|
||||
|
||||
def self.date_tuples(from,to)
|
||||
prec = from.size
|
||||
start = Date.new(*from)
|
||||
finish = Date.new(*to)
|
||||
|
||||
filter_on = [:day,:mon].first(3-prec)
|
||||
filter = ->(d) { filter_on.all? {|attr| d.send(attr) == 1 } }
|
||||
|
||||
(start..finish)
|
||||
.select(&filter)
|
||||
.map { |d| [d.year,d.mon,d.day].first(prec) }
|
||||
end
|
||||
|
||||
def self.earliest_cohort
|
||||
starting = User.where(admin: false).order(:created_at).first.created_at
|
||||
starting = EARLIEST_DATE if starting.nil? || starting < EARLIEST_DATE
|
||||
starting # this is necessary to always return not null
|
||||
end
|
||||
|
||||
def self.cohort_group_ranges(starting=nil, ending=nil)
|
||||
starting ||= self.earliest_cohort
|
||||
ending ||= Time.now
|
||||
dates = self.date_tuples([starting.year, starting.month], [ending.year, ending.month])
|
||||
ranges = []
|
||||
dates.each_with_index do |d1, idx|
|
||||
d2 = dates[idx+1] || [Time.now.next_month.year,Time.now.next_month.month]
|
||||
rr = Time.parse("#{d1[0]}-#{d1[1]}-1")..(Time.parse("#{d2[0]}-#{d2[1]}-1") - 1.second)
|
||||
ranges << rr
|
||||
end
|
||||
ranges
|
||||
end
|
||||
|
||||
def self.generate_monthly_cohorts(monthly_start, monthly_end)
|
||||
Cohort.delete_all(['all_time = ?',false])
|
||||
self.cohort_group_ranges.collect do |range|
|
||||
next if range.first > monthly_end
|
||||
cc = Cohort.new
|
||||
cc.group_start = range.first
|
||||
cc.group_end = range.last
|
||||
cc.monthly_start = monthly_start
|
||||
cc.monthly_end = monthly_end
|
||||
cc.all_time = false
|
||||
cc.save!
|
||||
cc
|
||||
end
|
||||
end
|
||||
|
||||
def self.generate_all_time_cohorts
|
||||
Cohort.delete_all("all_time = 't'")
|
||||
self.cohort_group_ranges.collect do |range|
|
||||
unless cc = Cohort.where(group_start: range.first).where(all_time: true).limit(1).first
|
||||
cc = Cohort.new
|
||||
cc.group_start = range.first
|
||||
cc.group_end = range.last
|
||||
cc.all_time = true
|
||||
cc.save!
|
||||
end
|
||||
cc
|
||||
end
|
||||
end
|
||||
|
||||
def _put_data_set(key, count, num_user)
|
||||
self.data_set[key.to_s] = count
|
||||
xx = (count.to_f / num_user.to_f)
|
||||
self.data_set["#{key}%"] = 100.0 * xx.round(2)
|
||||
end
|
||||
|
||||
def self.cohort_users(cohort)
|
||||
User.where(created_at: cohort.group_start..cohort.group_end)
|
||||
end
|
||||
|
||||
def _played_online_subquery(constraint)
|
||||
where = if constraint.is_a?(Range)
|
||||
"played.cnt >= #{constraint.first} AND played.cnt <= #{constraint.last}"
|
||||
else
|
||||
"played.cnt #{constraint}"
|
||||
end
|
||||
start_date = all_time ? self.group_start : self.monthly_start
|
||||
end_date = all_time ? self.group_end : self.monthly_end
|
||||
sql =<<SQL
|
||||
SELECT played.user_id FROM
|
||||
(SELECT user_id, COUNT(*) cnt FROM music_sessions_user_history msuh1
|
||||
WHERE
|
||||
msuh1.created_at >= '#{start_date}' AND
|
||||
msuh1.created_at <= '#{end_date}' AND
|
||||
EXTRACT(EPOCH FROM (msuh1.session_removed_at - msuh1.created_at)) >= 900 AND
|
||||
(SELECT COUNT(*) FROM music_sessions_user_history msuh2
|
||||
WHERE msuh1.music_session_id = msuh2.music_session_id
|
||||
) > 1
|
||||
GROUP BY user_id
|
||||
) played
|
||||
WHERE #{where}
|
||||
SQL
|
||||
end
|
||||
|
||||
def _played_jamtrack_subquery(constraint)
|
||||
where = if constraint.is_a?(Range)
|
||||
"played.cnt >= #{constraint.first} AND played.cnt <= #{constraint.last}"
|
||||
else
|
||||
"played.cnt #{constraint}"
|
||||
end
|
||||
start_date = all_time ? self.group_start : self.monthly_start
|
||||
end_date = all_time ? self.group_end : self.monthly_end
|
||||
sql =<<SQL
|
||||
SELECT played.player_id FROM
|
||||
(SELECT player_id, COUNT(*) cnt FROM playable_plays pp
|
||||
WHERE
|
||||
pp.created_at >= '#{start_date}' AND
|
||||
pp.created_at <= '#{end_date}' AND
|
||||
pp.playable_type = 'JamRuby::JamTrack'
|
||||
GROUP BY player_id
|
||||
) played
|
||||
WHERE #{where}
|
||||
SQL
|
||||
end
|
||||
|
||||
def _subquery(assoc_key, num_user)
|
||||
assoc = User.reflections[assoc_key]
|
||||
return 0 unless assoc
|
||||
start_date = all_time ? self.group_start : self.monthly_start
|
||||
end_date = all_time ? self.group_end : self.monthly_end
|
||||
sql =<<SQL
|
||||
SELECT #{assoc.foreign_key} FROM #{assoc.class_name.constantize.table_name} tt
|
||||
WHERE
|
||||
tt.created_at >= '#{start_date}' AND
|
||||
tt.created_at <= '#{end_date}'
|
||||
SQL
|
||||
yield(sql) if block_given?
|
||||
self.class.cohort_users(self).where("users.id IN (#{sql})").count
|
||||
end
|
||||
|
||||
def _monthly!
|
||||
unless 0 < num_user = self.class.cohort_users(self).count
|
||||
self.update_attribute(:data_set, {})
|
||||
return
|
||||
end
|
||||
|
||||
self.data_set['registered_users'] = num_user
|
||||
num_user = num_user.to_f
|
||||
|
||||
qq = self.class.cohort_users(self)
|
||||
.where(first_downloaded_client_at: self.monthly_start..self.monthly_end)
|
||||
_put_data_set(:first_downloaded_client_at, qq.count, num_user)
|
||||
|
||||
qq = self.class.cohort_users(self)
|
||||
.where(first_certified_gear_at: self.monthly_start..self.monthly_end)
|
||||
_put_data_set(:first_certified_gear_at, qq.count, num_user)
|
||||
|
||||
count = _subquery(assoc_key = :invited_users, num_user)
|
||||
_put_data_set(assoc_key, count, num_user)
|
||||
|
||||
count = _subquery(assoc_key = :recorded_tracks, num_user)
|
||||
_put_data_set(assoc_key, count, num_user)
|
||||
|
||||
count = _subquery(assoc_key = :jam_track_rights, num_user) do |subsql|
|
||||
subsql += " AND tt.redeemed = 'f' "
|
||||
end
|
||||
_put_data_set(assoc_key, count, num_user)
|
||||
|
||||
count = _subquery(assoc_key = :jam_track_rights, num_user) do |subsql|
|
||||
subsql += " AND tt.redeemed = 't' "
|
||||
end
|
||||
_put_data_set(:jam_track_rights_redeemed, count, num_user)
|
||||
|
||||
count = _subquery(assoc_key = :friendships, num_user)
|
||||
_put_data_set(assoc_key, count, num_user)
|
||||
|
||||
sql = _played_online_subquery(' = 1 ')
|
||||
count = self.class.cohort_users(self).where("users.id IN (#{sql})").count
|
||||
_put_data_set(:music_sessions_user_history_1, count, num_user)
|
||||
|
||||
sql = _played_online_subquery(2..5)
|
||||
count = self.class.cohort_users(self).where("users.id IN (#{sql})").count
|
||||
_put_data_set(:music_sessions_user_history_2_5, count, num_user)
|
||||
|
||||
sql = _played_online_subquery(' >= 6')
|
||||
count = self.class.cohort_users(self).where("users.id IN (#{sql})").count
|
||||
_put_data_set(:music_sessions_user_history_6_, count, num_user)
|
||||
|
||||
sql = _played_jamtrack_subquery(' = 1 ')
|
||||
count = self.class.cohort_users(self).where("users.id IN (#{sql})").count
|
||||
_put_data_set(:jam_tracks_played_1, count, num_user)
|
||||
|
||||
sql = _played_jamtrack_subquery(2..5)
|
||||
count = self.class.cohort_users(self).where("users.id IN (#{sql})").count
|
||||
_put_data_set(:jam_tracks_played_2_5, count, num_user)
|
||||
|
||||
sql = _played_jamtrack_subquery(' >= 6')
|
||||
count = self.class.cohort_users(self).where("users.id IN (#{sql})").count
|
||||
_put_data_set(:jam_tracks_played_6_, count, num_user)
|
||||
|
||||
self.save!
|
||||
end
|
||||
|
||||
def _join_user_all_time(assoc_ref)
|
||||
assoc_ref.active_record
|
||||
.joins("INNER JOIN users AS uu ON uu.id = #{assoc_ref.foreign_key}")
|
||||
.where(created_at: self.group_start..self.group_end)
|
||||
.where(['uu.created_at >= ? AND uu.created_at <= ?', self.group_start, self.group_end])
|
||||
end
|
||||
|
||||
def _all_time!
|
||||
unless 0 < num_user = self.class.cohort_users(self).count
|
||||
self.update_attribute(:data_set, {})
|
||||
return
|
||||
end
|
||||
|
||||
self.data_set['registered_users'] = num_user
|
||||
num_user = num_user.to_f
|
||||
|
||||
count = self.class.cohort_users(self)
|
||||
.where(['first_downloaded_client_at IS NOT NULL'])
|
||||
.count
|
||||
_put_data_set('first_downloaded_client_at', count, num_user)
|
||||
|
||||
count = self.class.cohort_users(self)
|
||||
.where(['first_certified_gear_at IS NOT NULL'])
|
||||
.count
|
||||
_put_data_set('first_certified_gear_at', count, num_user)
|
||||
|
||||
count = _subquery(assoc_key = :invited_users, num_user)
|
||||
_put_data_set(assoc_key, count, num_user)
|
||||
|
||||
count = _subquery(assoc_key = :recorded_tracks, num_user)
|
||||
_put_data_set(assoc_key, count, num_user)
|
||||
|
||||
count = _subquery(assoc_key = :friendships, num_user)
|
||||
_put_data_set(assoc_key, count, num_user)
|
||||
|
||||
count = _subquery(assoc_key = :jam_track_rights, num_user)
|
||||
_put_data_set(assoc_key, count, num_user)
|
||||
|
||||
count = _subquery(assoc_key = :jam_tracks_played, num_user) do |subsql|
|
||||
subsql += " AND tt.playable_type = 'JamRuby::JamTrack' "
|
||||
end
|
||||
_put_data_set(assoc_key, count, num_user)
|
||||
|
||||
sql = _played_online_subquery(' >= 1')
|
||||
count = self.class.cohort_users(self).where("users.id IN (#{sql})").count
|
||||
_put_data_set(:music_sessions_user_history, count, num_user)
|
||||
|
||||
self.save!
|
||||
end
|
||||
|
||||
def populate!
|
||||
self.all_time ? _all_time! : _monthly!
|
||||
end
|
||||
|
||||
def calculate_totals(cohorts)
|
||||
self.group_start = self.group_end = TOTAL_COHORT_DATE
|
||||
labels = all_time ? Cohort::ALLTIME_LABELS : Cohort::MONTHLY_LABELS
|
||||
|
||||
self.data_set = labels.inject({}) do |hh, (kk,vv)|
|
||||
hh[kk.to_s] = hh["#{kk}%"] = 0
|
||||
hh
|
||||
end
|
||||
|
||||
labels = labels.keys.map(&:to_s)
|
||||
cohorts.each do |cc|
|
||||
labels.each do |key|
|
||||
self.data_set[key] += cc.data_set[key].to_i
|
||||
end
|
||||
end
|
||||
|
||||
user_total = self.data_set['registered_users'].to_f
|
||||
labels.delete('registered_users')
|
||||
labels.each do |key|
|
||||
xx = (self.data_set[key].to_f / user_total)
|
||||
self.data_set["#{key}%"] = 100.0 * xx.round(4)
|
||||
end
|
||||
|
||||
self.save!
|
||||
cohorts << self
|
||||
end
|
||||
|
||||
def self.alltime_cohorts!
|
||||
cohorts = Cohort.generate_all_time_cohorts.each do |cc|
|
||||
cc._all_time!
|
||||
end
|
||||
Cohort.new(all_time: true).calculate_totals(cohorts)
|
||||
end
|
||||
|
||||
def self.monthly_cohorts!(monthly_start, monthly_end=nil)
|
||||
monthly_end ||= monthly_start + 1.month - 1.second
|
||||
cohorts = self.generate_monthly_cohorts(monthly_start, monthly_end).compact.each do |cc|
|
||||
cc._monthly!
|
||||
end
|
||||
Cohort.new(all_time: false, monthly_start: monthly_start).calculate_totals(cohorts)
|
||||
end
|
||||
|
||||
def group_start_str
|
||||
is_total_cohort? ? 'Total' : self.group_start.strftime('%Y-%m')
|
||||
end
|
||||
|
||||
def group_end_str
|
||||
self.group_end.strftime('%Y-%m-%d')
|
||||
end
|
||||
|
||||
def data_val(col, percent=false)
|
||||
if percent
|
||||
val = self.data_set["#{col}%"]
|
||||
val ? "#{'%0.f' % val}%" : ''
|
||||
else
|
||||
self.data_set[col.to_s]
|
||||
end
|
||||
end
|
||||
|
||||
def self.monthly_starts
|
||||
self.cohort_group_ranges.collect do |rr|
|
||||
rr.first.to_s
|
||||
end
|
||||
end
|
||||
|
||||
def is_total_cohort?
|
||||
self.group_start == TOTAL_COHORT_DATE
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
|
@ -4,27 +4,29 @@
|
|||
= f.input :name, :input_html => { :rows=>1, :maxlength=>200 }
|
||||
= f.input :description, :input_html => { :rows=>5, :maxlength=>1000 }
|
||||
= 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 media in the JamTrack. Changing JMEP does not count as a version change; changing anything about a track (audio, instrument, part) does.'
|
||||
//= f.input :initial_play_silence, :label => 'Initial Play Silence (seconds)'
|
||||
= f.input :time_signature, collection: JamRuby::JamTrack::TIME_SIGNATURES, include_blank: false
|
||||
= f.input :time_signature, collection: JamRuby::JamTrack::TIME_SIGNATURES, include_blank: true
|
||||
= f.input :status, collection: JamRuby::JamTrack::STATUS, include_blank: false, hint: 'Only set to Production when end users should be able to purchase this JamTrack'
|
||||
= f.input :recording_type, collection: JamRuby::JamTrack::RECORDING_TYPE, include_blank: false
|
||||
= f.input :original_artist, :input_html => { :rows=>1, :maxlength=>1000 }
|
||||
= f.input :songwriter, :input_html => { :rows=>1, :maxlength=>1000 }
|
||||
= f.input :publisher, :input_html => { :rows=>1, :maxlength=>1000 }
|
||||
= f.input :licensor, collection: JamRuby::JamTrackLicensor.all, include_blank: false
|
||||
= f.input :pro, collection: JamRuby::JamTrack::PRO, include_blank: false
|
||||
= f.input :licensor, collection: JamRuby::JamTrackLicensor.all, include_blank: true
|
||||
= f.input :genre, collection: JamRuby::Genre.all, include_blank: false
|
||||
= f.input :sales_region, collection: JamRuby::JamTrack::SALES_REGION, include_blank: false
|
||||
= f.input :price, :required=>true, :input_html=>{type:'numeric'}
|
||||
= f.input :price, :required => true, :input_html => {type: 'numeric'}
|
||||
= f.input :pro_ascap, :label => 'ASCAP royalties due?'
|
||||
= f.input :pro_bmi, :label => 'BMI royalties due?'
|
||||
= f.input :pro_sesac, :label => 'SESAC royalties due?'
|
||||
= f.input :reproduction_royalty, :label => 'Reproduction Royalty'
|
||||
= f.input :public_performance_royalty, :label => 'Public Performance Royalty'
|
||||
= 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 :url, :as => :file, :label => 'Audio File'
|
||||
= f.input :jmep_text, :as => :text, :label => "JMEP Text", :input_html => {:rows => 5 }, :hint => 'Tap-Ins & Lead Silence. Examples: https://jamkazam.atlassian.net/wiki/pages/viewpage.action?pageId=39289025#JamKazamMeta-EventProcessor(JMEP)-CommonExamples'
|
||||
= f.input :jmep_json, :as => :text, :label => "JMEP Json", :input_html => {:rows => 5, :readonly => true }, :hint => 'Readonly field. This is shown here just so you can see what your JMEP got converted to readily'
|
||||
= f.input :version, :label => 'Version', :hint => 'Increment this value whenever you invalidate (update) the media in the JamTrack. Changing JMEP does not count as a version change; changing anything about a track (audio, instrument, part) does.'
|
||||
|
||||
= f.semantic_fields_for :jam_track_tracks do |track|
|
||||
= render 'jam_track_track_fields', f: track
|
||||
|
|
|
|||
|
|
@ -4,24 +4,29 @@
|
|||
= f.input :track_type, :as => :select, collection: ['Track', 'Master'], include_blank: false
|
||||
= f.input :instrument, collection: Instrument.all, include_blank: false
|
||||
= f.input :part, :required=>true, :input_html => { :rows=>1, :maxlength=>20, :type=>'numeric' }
|
||||
|
||||
= f.input :position
|
||||
= f.input :preview_start_time_raw, :label => 'Preview Start Time', :hint => 'MM:SS:MLS', :as => :string
|
||||
- unless f.object.nil? || f.object[:preview_url].nil?
|
||||
.current_file_holder style='margin-bottom:10px'
|
||||
a href=f.object.preview_sign_url(3600) style='padding:0 0 0 20px'
|
||||
| Download Preview
|
||||
|
||||
// temporarily disable
|
||||
- if f.object.new_record?
|
||||
p style='margin-left:10px'
|
||||
i
|
||||
| before you can upload, you must select 'Update JamTrack'
|
||||
//p style='margin-left:10px'
|
||||
//i
|
||||
// | before you can upload, you must select 'Update JamTrack'
|
||||
- else
|
||||
= f.input :url_48, :as => :file, :label => 'Track file (48kHz)'
|
||||
// = f.input :url_48, :as => :file, :label => 'Track file (48kHz)'
|
||||
- unless f.object.nil? || f.object[:url_48].nil?
|
||||
.current_file_holder style='margin-bottom:10px'
|
||||
a href=f.object.sign_url(3600) style='padding:0 0 0 20px'
|
||||
| Download
|
||||
| #{File.basename(f.object[:url_48])}
|
||||
|
||||
= f.input :url_44, :as => :file, :label => 'Track file (44kHz)'
|
||||
// = f.input :url_44, :as => :file, :label => 'Track file (44kHz)'
|
||||
- unless f.object.nil? || f.object[:url_44].nil?
|
||||
.current_file_holder style='margin-bottom:10px'
|
||||
a href=f.object.sign_url(3600, 44) style='padding:0 0 0 20px'
|
||||
| Download
|
||||
| #{File.basename(f.object[:url_44])}
|
||||
|
||||
= link_to_remove_association "Delete Track", f, class: 'button', style: 'margin-left:10px'
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
class JamRuby::JamTrackTrack
|
||||
|
||||
# add a custom validation
|
||||
|
||||
attr_accessor :preview_generate_error
|
||||
|
||||
validate :preview
|
||||
|
||||
def preview
|
||||
if preview_generate_error
|
||||
errors.add(:preview_start_time, preview_generate_error)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
# this is used by active admin/jam-admin
|
||||
def preview_start_time_raw
|
||||
if self.preview_start_time.nil? || self.preview_start_time.nil?
|
||||
''
|
||||
else
|
||||
seconds = self.preview_start_time.to_f/1000
|
||||
time = Time.at(seconds)
|
||||
time.strftime("%M:%S:#{(self.preview_start_time % 1000).to_s.rjust(3, '0')}")
|
||||
end
|
||||
end
|
||||
|
||||
# this is used by active admin/jam-admin
|
||||
def preview_start_time_raw=(new_value)
|
||||
|
||||
value = nil
|
||||
if new_value == nil || new_value == ''
|
||||
value = nil
|
||||
else
|
||||
if new_value && new_value.kind_of?(String) && new_value.include?(':')
|
||||
bits = new_value.split(':')
|
||||
if bits.length != 3
|
||||
raise "format of preview start time must be MM:SS:MLS"
|
||||
end
|
||||
|
||||
value = (bits[0].to_i * 60000) + (bits[1].to_i * 1000) + (bits[2].to_i)
|
||||
|
||||
else
|
||||
raise "format of preview start time must be MM:SS:MLS"
|
||||
end
|
||||
end
|
||||
|
||||
if !value.nil? && value != self.preview_start_time
|
||||
self.preview_start_time = value
|
||||
generate_preview
|
||||
else
|
||||
self.preview_start_time = value
|
||||
end
|
||||
end
|
||||
|
||||
def generate_preview
|
||||
|
||||
begin
|
||||
Dir.mktmpdir do |tmp_dir|
|
||||
|
||||
input = File.join(tmp_dir, 'in.ogg')
|
||||
output = File.join(tmp_dir, 'out.ogg')
|
||||
|
||||
start = self.preview_start_time.to_f / 1000
|
||||
stop = start + 20
|
||||
|
||||
raise 'no track' unless self["url_44"]
|
||||
|
||||
s3_manager.download(self.url_by_sample_rate(44), input)
|
||||
|
||||
command = "sox \"#{input}\" \"#{output}\" trim #{start} #{stop}"
|
||||
|
||||
@@log.debug("trimming using: " + command)
|
||||
|
||||
sox_output = `#{command}`
|
||||
|
||||
result_code = $?.to_i
|
||||
|
||||
if result_code != 0
|
||||
@@log.debug("fail #{result_code}")
|
||||
@preview_generate_error = "unable to execute cut command #{sox_output}"
|
||||
else
|
||||
@@log.debug("uploading preview to #{self.preview_filename}")
|
||||
|
||||
s3_manager.upload(self.preview_filename, output)
|
||||
|
||||
self.skip_uploader = true
|
||||
# and finally update the JamTrackTrack with the new info
|
||||
self["preview_url"] = self.preview_filename
|
||||
self["preview_md5"] = ::Digest::MD5.file(output).hexdigest
|
||||
self["preview_length"] = File.new(output).size
|
||||
self.save!
|
||||
end
|
||||
end
|
||||
rescue Exception => e
|
||||
@@log.error("error in sox command #{e.to_s}")
|
||||
@preview_generate_error = e.to_s
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -2,6 +2,8 @@ class JamRuby::JamTrack
|
|||
|
||||
# add a custom validation
|
||||
|
||||
attr_accessor :preview_generate_error
|
||||
|
||||
before_save :jmep_json_generate
|
||||
validate :jmep_text_validate
|
||||
|
||||
|
|
@ -14,12 +16,15 @@ class JamRuby::JamTrack
|
|||
end
|
||||
|
||||
def jmep_json_generate
|
||||
self.genre_id = nil if self.genre_id == ''
|
||||
self.licensor_id = nil if self.licensor_id == ''
|
||||
self.jmep_json = nil if self.jmep_json == ''
|
||||
self.time_signature = nil if self.time_signature == ''
|
||||
|
||||
begin
|
||||
self[:jmep_json] = JmepManager.execute(self.jmep_text)
|
||||
rescue ArgumentError => err
|
||||
#errors.add(:jmep_text, err.to_s)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ FactoryGirl.define do
|
|||
scoring_timeout Time.now
|
||||
sequence(:channel_id) { |n| "Channel#{n}"}
|
||||
association :user, factory: :user
|
||||
metronome_open false
|
||||
end
|
||||
|
||||
factory :artifact_update, :class => JamRuby::ArtifactUpdate do
|
||||
|
|
|
|||
|
|
@ -263,4 +263,11 @@ recorded_jam_track_tracks.sql
|
|||
jam_track_jmep_data.sql
|
||||
add_jam_track_bitrates.sql
|
||||
jam_track_importer.sql
|
||||
jam_track_pro_licensing_update.sql
|
||||
jam_track_redeemed.sql
|
||||
connection_metronome.sql
|
||||
preview_jam_track_tracks.sql
|
||||
cohorts.sql
|
||||
jam_track_right_admin_purchase.sql
|
||||
alter_genre_player_unique_constraint.sql
|
||||
musician_search.sql
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE genre_players DROP CONSTRAINT genre_player_uniqkey;
|
||||
ALTER TABLE genre_players ADD CONSTRAINT genre_player_uniqkey UNIQUE (player_id, player_type, genre_id, genre_type);
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
CREATE TABLE cohorts (
|
||||
id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
|
||||
data_set JSON NOT NULL DEFAULT '{}',
|
||||
|
||||
group_start TIMESTAMP NOT NULL,
|
||||
group_end TIMESTAMP NOT NULL,
|
||||
|
||||
all_time BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
monthly_start TIMESTAMP,
|
||||
monthly_end TIMESTAMP,
|
||||
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE INDEX index_group_date ON cohorts USING btree (group_start);
|
||||
|
||||
CREATE INDEX msuh_music_session_idx ON music_sessions_user_history USING btree(music_session_id);
|
||||
|
|
@ -0,0 +1 @@
|
|||
ALTER TABLE connections ADD COLUMN metronome_open BOOLEAN NOT NULL DEFAULT FALSE;
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
ALTER TABLE jam_tracks ADD COLUMN pro_ascap BOOLEAN DEFAULT FALSE NOT NULL;
|
||||
ALTER TABLE jam_tracks ADD COLUMN pro_bmi BOOLEAN DEFAULT FALSE NOT NULL;
|
||||
ALTER TABLE jam_tracks ADD COLUMN pro_sesac BOOLEAN DEFAULT FALSE NOT NULL;
|
||||
UPDATE jam_tracks SET pro_ascap = TRUE WHERE pro = 'ASCAP';
|
||||
UPDATE jam_tracks SET pro_bmi = TRUE WHERE pro = 'BMI';
|
||||
UPDATE jam_tracks SET pro_sesac = TRUE WHERE pro = 'SESAC';
|
||||
ALTER TABLE jam_tracks DROP COLUMN pro;
|
||||
ALTER TABLE jam_tracks DROP Column pro_royalty_amount;
|
||||
ALTER TABLE jam_tracks ADD COLUMN preview_start_time INTEGER;
|
||||
ALTER TABLE jam_tracks RENAME COLUMN url TO preview_url;
|
||||
ALTER TABLE jam_tracks RENAME COLUMN md5 TO preview_md5;
|
||||
ALTER TABLE jam_tracks RENAME COLUMN length TO preview_length;
|
||||
|
|
@ -0,0 +1 @@
|
|||
ALTER TABLE jam_track_rights ADD COLUMN redeemed BOOLEAN NOT NULL DEFAULT FALSE;
|
||||
|
|
@ -0,0 +1 @@
|
|||
ALTER TABLE jam_track_rights ADD COLUMN is_test_purchase BOOLEAN DEFAULT FALSE NOT NULL;
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
ALTER TABLE jam_tracks DROP COLUMN preview_url;
|
||||
ALTER TABLE jam_tracks DROP COLUMN preview_md5;
|
||||
ALTER TABLE jam_tracks DROP COLUMN preview_length;
|
||||
ALTER TABLE jam_tracks DROP COLUMN preview_start_time;
|
||||
|
||||
ALTER TABLE jam_track_tracks ADD COLUMN preview_url VARCHAR;
|
||||
ALTER TABLE jam_track_tracks ADD COLUMN preview_md5 VARCHAR;
|
||||
ALTER TABLE jam_track_tracks ADD COLUMN preview_length BIGINT;
|
||||
ALTER TABLE jam_track_tracks ADD COLUMN preview_start_time INTEGER;
|
||||
|
|
@ -11,7 +11,7 @@ class JamTrackUploader < CarrierWave::Uploader::Base
|
|||
|
||||
# Add a white list of extensions which are allowed to be uploaded.
|
||||
def extension_white_list
|
||||
%w(jkz)
|
||||
%w(ogg)
|
||||
end
|
||||
|
||||
def store_dir
|
||||
|
|
@ -23,6 +23,6 @@ class JamTrackUploader < CarrierWave::Uploader::Base
|
|||
end
|
||||
|
||||
def filename
|
||||
"#{model.store_dir}/#{model.filename}" if model.id
|
||||
"#{model.preview_filename}" if model.id && model.uploading_preview
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ module JamRuby
|
|||
udp_reachable_value = udp_reachable.nil? ? 'udp_reachable' : udp_reachable
|
||||
|
||||
sql =<<SQL
|
||||
UPDATE connections SET (channel_id, aasm_state, updated_at, music_session_id, joined_session_at, stale_time, expire_time, udp_reachable, gateway, is_network_testing) = ('#{channel_id}', '#{Connection::CONNECT_STATE.to_s}', NOW(), #{music_session_id_expression}, #{joined_session_at_expression}, #{connection_stale_time}, #{connection_expire_time}, #{udp_reachable_value}, '#{gateway}', FALSE)
|
||||
UPDATE connections SET (channel_id, aasm_state, updated_at, music_session_id, joined_session_at, stale_time, expire_time, udp_reachable, gateway, is_network_testing, metronome_open) = ('#{channel_id}', '#{Connection::CONNECT_STATE.to_s}', NOW(), #{music_session_id_expression}, #{joined_session_at_expression}, #{connection_stale_time}, #{connection_expire_time}, #{udp_reachable_value}, '#{gateway}', FALSE, FALSE)
|
||||
WHERE
|
||||
client_id = '#{conn.client_id}'
|
||||
RETURNING music_session_id
|
||||
|
|
|
|||
|
|
@ -102,7 +102,6 @@ module JamRuby
|
|||
jam_track.price = 1.99
|
||||
jam_track.reproduction_royalty_amount = 0
|
||||
jam_track.licensor_royalty_amount = 0
|
||||
jam_track.pro_royalty_amount = 0
|
||||
jam_track.sales_region = 'United States'
|
||||
jam_track.recording_type = 'Cover'
|
||||
jam_track.description = "This is a JamTrack audio file for use exclusively with the JamKazam service. This JamTrack is a high quality cover of the #{jam_track.original_artist} song \"#{jam_track.name}\"."
|
||||
|
|
|
|||
|
|
@ -34,9 +34,9 @@ module JamRuby
|
|||
nm = jam_track_track.id + File.extname(jam_track_track.url_by_sample_rate(sample_rate))
|
||||
track_filename = File.join(tmp_dir, nm)
|
||||
track_url = jam_track_track.sign_url(120, sample_rate)
|
||||
@@log.info("downloading #{track_url} to #{track_filename}")
|
||||
copy_url_to_file(track_url, track_filename)
|
||||
copy_url_to_file(track_url, File.join(".", nm))
|
||||
jam_file_opts << " -i '#{track_filename}+#{jam_track_track.part}'"
|
||||
jam_file_opts << " -i #{Shellwords.escape("#{track_filename}+#{jam_track_track.part}")}"
|
||||
end
|
||||
#puts "LS + " + `ls -la '#{tmp_dir}'`
|
||||
|
||||
|
|
@ -46,9 +46,9 @@ module JamRuby
|
|||
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}' -V '#{version}'"
|
||||
cli = "python #{py_file} -D -k #{sku} -p #{Shellwords.escape(tmp_dir)}/pkey.pem -s #{Shellwords.escape(tmp_dir)}/skey.pem #{jam_file_opts} -o #{Shellwords.escape(output_jkz)} -t #{Shellwords.escape(title)} -V #{Shellwords.escape(version)}"
|
||||
Open3.popen3(cli) do |stdin, stdout, stderr, wait_thr|
|
||||
pid = wait_thr.pid
|
||||
exit_status = wait_thr.value
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ module JamRuby
|
|||
has_many :backing_tracks, :class_name => "JamRuby::BackingTrack", :inverse_of => :connection, :foreign_key => 'connection_id', :dependent => :delete_all
|
||||
has_many :video_sources, :class_name => "JamRuby::VideoSource", :inverse_of => :connection, :foreign_key => 'connection_id', :dependent => :delete_all
|
||||
|
||||
validates :metronome_open, :inclusion => {:in => [true, false]}
|
||||
validates :as_musician, :inclusion => {:in => [true, false, nil]}
|
||||
validates :client_type, :inclusion => {:in => CLIENT_TYPES}
|
||||
validates_numericality_of :last_jam_audio_latency, greater_than:0, :allow_nil => true
|
||||
|
|
|
|||
|
|
@ -12,35 +12,34 @@ module JamRuby
|
|||
|
||||
@@log = Logging.logger[JamTrack]
|
||||
|
||||
mount_uploader :url, JamTrackUploader
|
||||
|
||||
attr_accessor :uploading_preview
|
||||
attr_accessible :name, :description, :bpm, :time_signature, :status, :recording_type,
|
||||
: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, :version, :jmep_json, :jmep_text, as: :admin
|
||||
:jam_track_tap_ins_attributes, :version, :jmep_json, :jmep_text, :pro_ascap, :pro_bmi, :pro_sesac, as: :admin
|
||||
|
||||
validates :name, presence: true, uniqueness: true, length: {maximum: 200}
|
||||
validates :plan_code, presence: true, uniqueness: true, length: {maximum: 50 }
|
||||
validates :description, length: {maximum: 1000}
|
||||
validates :time_signature, inclusion: {in: [nil] + TIME_SIGNATURES}
|
||||
validates :time_signature, inclusion: {in: [nil] + [''] + TIME_SIGNATURES} # the empty string is needed because of activeadmin
|
||||
validates :status, inclusion: {in: [nil] + STATUS}
|
||||
validates :recording_type, inclusion: {in: [nil] + RECORDING_TYPE}
|
||||
validates :original_artist, length: {maximum: 200}
|
||||
validates :songwriter, length: {maximum: 1000}
|
||||
validates :publisher, length: {maximum: 1000}
|
||||
validates :pro, inclusion: {in: [nil] + PRO}
|
||||
validates :sales_region, inclusion: {in: [nil] + SALES_REGION}
|
||||
validates_format_of :price, with: /^\d+\.*\d{0,2}$/
|
||||
validates :version, presence: true
|
||||
|
||||
validates :pro_ascap, inclusion: {in: [true, false]}
|
||||
validates :pro_bmi, inclusion: {in: [true, false]}
|
||||
validates :pro_sesac, inclusion: {in: [true, false]}
|
||||
validates :public_performance_royalty, inclusion: {in: [nil, true, false]}
|
||||
validates :reproduction_royalty, inclusion: {in: [nil, true, false]}
|
||||
validates :public_performance_royalty, inclusion: {in: [nil, true, false]}
|
||||
|
||||
validates_format_of :reproduction_royalty_amount, with: /^\d+\.*\d{0,3}$/
|
||||
validates_format_of :licensor_royalty_amount, with: /^\d+\.*\d{0,3}$/
|
||||
validates_format_of :pro_royalty_amount, with: /^\d+\.*\d{0,3}$/
|
||||
|
||||
before_save :sanitize_active_admin
|
||||
|
||||
belongs_to :genre, class_name: "JamRuby::Genre"
|
||||
belongs_to :licensor , class_name: 'JamRuby::JamTrackLicensor', foreign_key: 'licensor_id'
|
||||
|
|
@ -60,15 +59,27 @@ module JamRuby
|
|||
|
||||
class << self
|
||||
def index(options, user)
|
||||
limit = options[:limit]
|
||||
limit ||= 20
|
||||
limit = limit.to_i
|
||||
if options[:page]
|
||||
page = options[:page].to_i
|
||||
per_page = options[:per_page].to_i
|
||||
|
||||
start = (page -1 )* per_page
|
||||
limit = per_page
|
||||
else
|
||||
limit = options[:limit]
|
||||
limit ||= 20
|
||||
limit = limit.to_i
|
||||
|
||||
start = options[:start].presence
|
||||
start = start.to_i || 0
|
||||
|
||||
page = 1 + start/limit
|
||||
per_page = limit
|
||||
end
|
||||
|
||||
start = options[:start].presence
|
||||
start = start.to_i || 0
|
||||
|
||||
query = JamTrack.joins(:jam_track_tracks)
|
||||
.paginate(page: 1 + start/limit, per_page: limit)
|
||||
.paginate(page: page, per_page: per_page)
|
||||
|
||||
if options[:show_purchased_only]
|
||||
query = query.joins(:jam_track_rights)
|
||||
|
|
@ -91,26 +102,12 @@ module JamRuby
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
# create storage directory that will house this jam_track, as well as
|
||||
def store_dir
|
||||
"jam_tracks/#{id}"
|
||||
end
|
||||
|
||||
# create name of the file
|
||||
def filename
|
||||
"#{name}.jkz"
|
||||
end
|
||||
|
||||
# creates a short-lived URL that has access to the object.
|
||||
# the idea is that this is used when a user who has the rights to this tries to download this JamTrack
|
||||
# we would verify their rights (can_download?), and generates a URL in response to the click so that they can download
|
||||
# but the url is short lived enough so that it wouldn't be easily shared
|
||||
def sign_url(expiration_time = 120)
|
||||
s3_manager.sign_url(self[:url], {:expires => expiration_time, :response_content_type => 'audio/jkz', :secure => false})
|
||||
def master_track
|
||||
JamTrackTrack.where(jam_track_id: self.id).where(track_type: 'Master').first
|
||||
end
|
||||
|
||||
|
||||
def can_download?(user)
|
||||
owners.include?(user)
|
||||
end
|
||||
|
|
@ -118,50 +115,5 @@ module JamRuby
|
|||
def right_for_user(user)
|
||||
jam_track_rights.where("user_id=?", user).first
|
||||
end
|
||||
|
||||
def self.list_downloads(user, limit = 100, since = 0, bitrate = 48)
|
||||
since = 0 unless since || since == '' # guard against nil
|
||||
downloads = []
|
||||
|
||||
user.jam_track_rights
|
||||
.limit(limit)
|
||||
.where('jam_track_rights.id > ?', since)
|
||||
.each do |jam_track_right|
|
||||
download = {
|
||||
:type => "jam_track",
|
||||
:id => jam_track_right.id.to_s,
|
||||
:jam_track_id => jam_track_right.jam_track_id,
|
||||
:created_at => jam_track_right.created_at,
|
||||
:next => jam_track_right.id
|
||||
}
|
||||
if(bitrate==48)
|
||||
download[:length] = jam_track_right.length_48
|
||||
download[:md5] = jam_track_right.md5_48
|
||||
download[:url] = jam_track_right.url_48
|
||||
else
|
||||
download[:length] = jam_track_right.length_44
|
||||
download[:md5] = jam_track_right.md5_44
|
||||
download[:url] = jam_track_right.url_44
|
||||
end
|
||||
downloads << download
|
||||
end
|
||||
|
||||
next_id = downloads[-1][:next] if downloads.length > 0
|
||||
next_id = since if next_id.nil? # echo back to the client the same value they passed in, if there are no results
|
||||
|
||||
{
|
||||
'downloads' => downloads,
|
||||
'next' => next_id.to_s
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
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
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ module JamRuby
|
|||
|
||||
validates :user, presence:true
|
||||
validates :jam_track, presence:true
|
||||
validates :is_test_purchase, inclusion: {in: [true, false]}
|
||||
|
||||
validate :verify_download_count
|
||||
after_save :after_save
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,6 @@ module JamRuby
|
|||
else
|
||||
raise "format of offset time must be MM:SS:MLS"
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -7,17 +7,22 @@ module JamRuby
|
|||
# there should only be one Master per JamTrack, but there can be N Track per JamTrack
|
||||
TRACK_TYPE = %w{Track Master}
|
||||
|
||||
mount_uploader :url_48, JamTrackTrackUploader
|
||||
mount_uploader :url_44, JamTrackTrackUploader
|
||||
@@log = Logging.logger[JamTrackTrack]
|
||||
|
||||
|
||||
# Because JamTrackImporter imports audio files now, and because also the mere presence of this causes serious issues when updating the model (because reset of url_44 to something bogus), I've removed these
|
||||
#mount_uploader :url_48, JamTrackTrackUploader
|
||||
#mount_uploader :url_44, JamTrackTrackUploader
|
||||
|
||||
attr_accessible :jam_track_id, :track_type, :instrument, :instrument_id, :position, :part, as: :admin
|
||||
attr_accessible :url_44, :url_48, :md5_44, :md5_48, :length_44, :length_48, as: :admin
|
||||
attr_accessible :url_44, :url_48, :md5_44, :md5_48, :length_44, :length_48, :preview_start_time_raw, as: :admin
|
||||
|
||||
attr_accessor :original_audio_s3_path, :skip_uploader
|
||||
|
||||
validates :position, presence: true, numericality: {only_integer: true}, length: {in: 1..1000}
|
||||
validates :part, length: {maximum: 25}
|
||||
validates :track_type, inclusion: {in: TRACK_TYPE }
|
||||
validates :preview_start_time, numericality: {only_integer: true}, length: {in: 1..1000}, :allow_nil => true
|
||||
validates_uniqueness_of :position, scope: :jam_track_id
|
||||
validates_uniqueness_of :part, scope: [:jam_track_id, :instrument_id]
|
||||
# validates :jam_track, presence: true
|
||||
|
|
@ -37,6 +42,24 @@ module JamRuby
|
|||
"#{store_dir}/#{jam_track.original_artist}/#{jam_track.name}/#{original_name}"
|
||||
end
|
||||
|
||||
# create name of the file
|
||||
def preview_filename
|
||||
filename("#{File.basename(self["url_44"], ".ogg")}-preview.ogg")
|
||||
end
|
||||
|
||||
def has_preview?
|
||||
!self["preview_url"].nil?
|
||||
end
|
||||
|
||||
# creates a short-lived URL that has access to the object.
|
||||
# the idea is that this is used when a user who has the rights to this tries to download this JamTrack
|
||||
# we would verify their rights (can_download?), and generates a URL in response to the click so that they can download
|
||||
# but the url is short lived enough so that it wouldn't be easily shared
|
||||
def preview_sign_url(expiration_time = 120)
|
||||
s3_manager.sign_url(self[:preview_url], {:expires => expiration_time, :response_content_type => 'audio/ogg', :secure => false})
|
||||
end
|
||||
|
||||
|
||||
def manually_uploaded_filename(mounted_as)
|
||||
if track_type == 'Master'
|
||||
filename("Master Mix-#{mounted_as == :url_48 ? '48000' : '44100'}.ogg")
|
||||
|
|
|
|||
|
|
@ -141,12 +141,14 @@ 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" => 1.0, "balance" => 0 }
|
||||
mix_params << { "level" => 100, "balance" => 0 }
|
||||
# change to 1.0 level later
|
||||
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" => 1.0, "balance" => 0 }
|
||||
mix_params << { "level" => 100, "balance" => 0 }
|
||||
# change to 1.0 level later
|
||||
end
|
||||
|
||||
recording.recorded_jam_track_tracks.each do |recorded_jam_track_track|
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ module JamRuby
|
|||
|
||||
# this is a bit different from a normal track synchronization in that the client just sends up all tracks,
|
||||
# ... some may already exist
|
||||
def self.sync(clientId, tracks, backing_tracks = [])
|
||||
def self.sync(clientId, tracks, backing_tracks = [], metronome_open = false)
|
||||
result = {}
|
||||
|
||||
backing_tracks = [] unless backing_tracks
|
||||
|
|
@ -117,6 +117,11 @@ module JamRuby
|
|||
Track.transaction do
|
||||
connection = Connection.find_by_client_id!(clientId)
|
||||
|
||||
# synchronize metronome_open on connection
|
||||
if connection.metronome_open != metronome_open
|
||||
Connection.where(:id => connection.id).update_all(:metronome_open => metronome_open)
|
||||
end
|
||||
|
||||
# each time tracks are synced we have to update the entry in music_sessions_user_history
|
||||
msh = MusicSessionUserHistory.find_by_client_id!(clientId)
|
||||
instruments = []
|
||||
|
|
|
|||
|
|
@ -660,7 +660,7 @@ module JamRuby
|
|||
end
|
||||
|
||||
online_presences.each do |op|
|
||||
op = OnlinePresence.create(self.id, online_presences, false)
|
||||
op = OnlinePresence.create(self, online_presences, false)
|
||||
self.online_presences << op
|
||||
end
|
||||
end
|
||||
|
|
@ -671,7 +671,7 @@ module JamRuby
|
|||
end
|
||||
|
||||
performance_samples.each do |ps|
|
||||
ps = PerformanceSample.create(self.id, performance_samples, false)
|
||||
ps = PerformanceSample.create(self, performance_samples, false)
|
||||
self.performance_samples << ps
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -730,14 +730,12 @@ FactoryGirl.define do
|
|||
sequence(:original_artist) { |n| "original-artist-#{n}" }
|
||||
sequence(:songwriter) { |n| "songwriter-#{n}" }
|
||||
sequence(:publisher) { |n| "publisher-#{n}" }
|
||||
pro 'ASCAP'
|
||||
sales_region 'United States'
|
||||
price 1.99
|
||||
reproduction_royalty true
|
||||
public_performance_royalty true
|
||||
reproduction_royalty_amount 0.999
|
||||
licensor_royalty_amount 0.999
|
||||
pro_royalty_amount 0.999
|
||||
sequence(:plan_code) { |n| "jamtrack-#{n}" }
|
||||
|
||||
genre JamRuby::Genre.first
|
||||
|
|
|
|||
|
|
@ -57,7 +57,6 @@ describe JamTrackImporter do
|
|||
jam_track.original_artist.should eq('Artist 1')
|
||||
jam_track.songwriter.should be_nil
|
||||
jam_track.publisher.should be_nil
|
||||
jam_track.pro.should be_nil
|
||||
jam_track.sales_region.should eq('United States')
|
||||
jam_track.price.should eq(1.99)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -17,14 +17,6 @@ describe JamTrackRight do
|
|||
|
||||
end
|
||||
|
||||
it "lists" do
|
||||
jam_track_right = FactoryGirl.create(:jam_track_right)
|
||||
jam_tracks = JamTrack.list_downloads(jam_track_right.user)
|
||||
jam_tracks.should have_key('downloads')
|
||||
jam_tracks.should have_key('next')
|
||||
jam_tracks['downloads'].should have(1).items
|
||||
end
|
||||
|
||||
describe "validations" do
|
||||
it "one purchase per user/jam_track combo" do
|
||||
user = FactoryGirl.create(:user)
|
||||
|
|
@ -66,15 +58,15 @@ describe JamTrackRight do
|
|||
user = FactoryGirl.create(:user)
|
||||
jam_track_track = FactoryGirl.create(:jam_track_track)
|
||||
jam_track = jam_track_track.jam_track
|
||||
|
||||
uploader = JamTrackTrackUploader.new(jam_track_track, :url_48)
|
||||
uploader.store!(File.open(ogg_path, 'rb'))
|
||||
|
||||
s3 = S3Manager.new(APP_CONFIG.aws_bucket, APP_CONFIG.aws_access_key_id, APP_CONFIG.aws_secret_access_key)
|
||||
|
||||
s3.upload(jam_track_track.manually_uploaded_filename(:url_48), ogg_path)
|
||||
jam_track_track[:url_48] = jam_track_track.manually_uploaded_filename(:url_48)
|
||||
jam_track_track.save!
|
||||
|
||||
jam_track_track[:url_48].should == jam_track_track.manually_uploaded_filename(:url_48)
|
||||
|
||||
# verify it's on S3
|
||||
s3 = S3Manager.new(APP_CONFIG.aws_bucket, APP_CONFIG.aws_access_key_id, APP_CONFIG.aws_secret_access_key)
|
||||
s3.exists?(jam_track_track[:url_48]).should be_true
|
||||
s3.length(jam_track_track[:url_48]).should == File.size?(ogg_path)
|
||||
|
||||
|
|
|
|||
|
|
@ -117,44 +117,5 @@ describe JamTrack do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "upload/download" do
|
||||
JKA_NAME = 'blah.jkz'
|
||||
|
||||
in_directory_with_file(JKA_NAME)
|
||||
|
||||
before(:all) do
|
||||
original_storage = JamTrackUploader.storage = :fog
|
||||
end
|
||||
|
||||
after(:all) do
|
||||
JamTrackUploader.storage = @original_storage
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
content_for_file('abc')
|
||||
end
|
||||
|
||||
it "uploads to s3 with correct name, and then downloads via signed URL" do
|
||||
jam_track = FactoryGirl.create(:jam_track)
|
||||
uploader = JamTrackUploader.new(jam_track, :url)
|
||||
uploader.store!(File.open(JKA_NAME)) # uploads file
|
||||
jam_track.save!
|
||||
|
||||
# verify that the uploader stores the correct path
|
||||
jam_track[:url].should == jam_track.store_dir + '/' + jam_track.filename
|
||||
|
||||
# verify it's on S3
|
||||
s3 = S3Manager.new(APP_CONFIG.aws_bucket, APP_CONFIG.aws_access_key_id, APP_CONFIG.aws_secret_access_key)
|
||||
s3.exists?(jam_track[:url]).should be_true
|
||||
s3.length(jam_track[:url]).should == 'abc'.length
|
||||
|
||||
# download it via signed URL, and check contents
|
||||
url = jam_track.sign_url
|
||||
downloaded_contents = open(url).read
|
||||
downloaded_contents.should == 'abc'
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -46,9 +46,11 @@ describe JamTrackTrack do
|
|||
end
|
||||
|
||||
it "uploads to s3 with correct name, and then downloads via signed URL" do
|
||||
s3 = S3Manager.new(APP_CONFIG.aws_bucket, APP_CONFIG.aws_access_key_id, APP_CONFIG.aws_secret_access_key)
|
||||
|
||||
jam_track_track = FactoryGirl.create(:jam_track_track)
|
||||
uploader = JamTrackTrackUploader.new(jam_track_track, :url_48)
|
||||
uploader.store!(File.open(TRACK_NAME)) # uploads file
|
||||
s3.upload(jam_track_track.manually_uploaded_filename(:url_48), TRACK_NAME)
|
||||
jam_track_track[:url_48] = jam_track_track.manually_uploaded_filename(:url_48)
|
||||
jam_track_track.save!
|
||||
jam_track_track.reload
|
||||
|
||||
|
|
@ -56,7 +58,6 @@ describe JamTrackTrack do
|
|||
jam_track_track[:url_48].should == jam_track_track.manually_uploaded_filename(:url_48)
|
||||
|
||||
# verify it's on S3
|
||||
s3 = S3Manager.new(APP_CONFIG.aws_bucket, APP_CONFIG.aws_access_key_id, APP_CONFIG.aws_secret_access_key)
|
||||
s3.exists?(jam_track_track[:url_48]).should be_true
|
||||
s3.length(jam_track_track[:url_48]).should == 'abc'.length
|
||||
|
||||
|
|
|
|||
|
|
@ -172,5 +172,21 @@ describe Track do
|
|||
expect(found.updated_at.to_i).to eq backing_track.updated_at.to_i
|
||||
end
|
||||
end
|
||||
|
||||
describe "metronome_open" do
|
||||
it "sets metronome_open to true" do
|
||||
result = Track.sync(connection.client_id, [track_hash], [], true)
|
||||
connection.reload
|
||||
connection.metronome_open.should be_true
|
||||
end
|
||||
|
||||
it "sets metronome_open to false" do
|
||||
connection.metronome_open = true
|
||||
connection.save!
|
||||
result = Track.sync(connection.client_id, [track_hash], [], false)
|
||||
connection.reload
|
||||
connection.metronome_open.should be_false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -27,8 +27,8 @@ describe JamTracksBuilder do
|
|||
jam_track_track = FactoryGirl.create(:jam_track_track)
|
||||
jam_track = jam_track_track.jam_track
|
||||
|
||||
#uploader = JamTrackTrackUploader.new(jam_track_track, :url_48)
|
||||
jam_track_track.url_48.store!(File.open(ogg_path, 'rb'))
|
||||
@s3.upload(jam_track_track.manually_uploaded_filename(:url_48), ogg_path)
|
||||
jam_track_track[:url_48] = jam_track_track.manually_uploaded_filename(:url_48)
|
||||
jam_track_track.save!
|
||||
|
||||
jam_track_track[:url_48].should == jam_track_track.manually_uploaded_filename(:url_48)
|
||||
|
|
@ -36,7 +36,7 @@ describe JamTracksBuilder do
|
|||
# verify it's on S3
|
||||
@s3.exists?(jam_track_track[:url_48]).should be_true
|
||||
@s3.length(jam_track_track[:url_48]).should == File.size?(ogg_path)
|
||||
@s3.exists?(jam_track_track[:url_44]).should be_false
|
||||
jam_track_track[:url_44].should be_nil
|
||||
|
||||
# Check right
|
||||
jam_track_right = JamTrackRight.create(:user=>user, :jam_track=>jam_track)
|
||||
|
|
@ -45,7 +45,7 @@ describe JamTracksBuilder do
|
|||
JamTracksBuilder.perform(jam_track_right.id, 48)
|
||||
jam_track_right.reload
|
||||
jam_track_right[:url_48].should == jam_track_right.store_dir + '/' + jam_track_right.filename
|
||||
@s3.exists?(jam_track_track[:url_44]).should be_false
|
||||
jam_track_track[:url_44].should be_nil
|
||||
end
|
||||
|
||||
describe "with bitrate 44" do
|
||||
|
|
@ -59,7 +59,8 @@ describe JamTracksBuilder do
|
|||
|
||||
# uploader = JamTrackTrackUploader.new(jam_track_track, :url_44)
|
||||
# uploader.store!(File.open(ogg_path, 'rb'))
|
||||
jam_track_track.url_44.store!(File.open(ogg_path, 'rb'))
|
||||
@s3.upload(jam_track_track.manually_uploaded_filename(:url_44), ogg_path)
|
||||
jam_track_track[:url_44] = jam_track_track.manually_uploaded_filename(:url_44)
|
||||
jam_track_track.save!
|
||||
|
||||
jam_track_track[:url_44].should == jam_track_track.manually_uploaded_filename(:url_44)
|
||||
|
|
@ -67,7 +68,7 @@ describe JamTracksBuilder do
|
|||
# verify it's on S3
|
||||
@s3.exists?(jam_track_track[:url_44]).should be_true
|
||||
@s3.length(jam_track_track[:url_44]).should == File.size?(ogg_path)
|
||||
@s3.exists?(jam_track_track[:url_48]).should be_false
|
||||
jam_track_track[:url_48].should be_nil
|
||||
|
||||
# Check right
|
||||
jam_track_right = JamTrackRight.create(:user=>user, :jam_track=>jam_track)
|
||||
|
|
@ -77,7 +78,7 @@ describe JamTracksBuilder do
|
|||
jam_track_right.reload
|
||||
jam_track_right[:url_44].should == jam_track_right.store_dir + '/' + jam_track_right.filename
|
||||
jam_track_right.url_44.should_not be_nil
|
||||
@s3.exists?(jam_track_track[:url_48]).should be_false
|
||||
jam_track_track[:url_48].should be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
Jasmine Javascript Unit Tests
|
||||
=============================
|
||||
|
||||
|
|
|
|||
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 828 B |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
|
@ -18,6 +18,9 @@
|
|||
var nilOptionStr = '<option value=""></option>';
|
||||
var nilOptionText = 'n/a';
|
||||
var $screen = $('#account-profile-basics');
|
||||
var $btnCancel = $screen.find('#account-edit-profile-cancel');
|
||||
var $btnSubmit = $screen.find('#account-edit-profile-submit');
|
||||
|
||||
var $biography = null;
|
||||
|
||||
function beforeShow(data) {
|
||||
|
|
@ -213,14 +216,24 @@
|
|||
/****************** MAIN PORTION OF SCREEN *****************/
|
||||
// events for main screen
|
||||
function events() {
|
||||
$('#account-profile-content-scroller').on('click', '#account-edit-profile-cancel', function(evt) { evt.stopPropagation(); navToAccount(); return false; } );
|
||||
$('#account-profile-content-scroller').on('click', '#account-edit-profile-submit', function(evt) { evt.stopPropagation(); handleUpdateProfile(); return false; } );
|
||||
$btnCancel.click(function(evt) {
|
||||
evt.stopPropagation();
|
||||
navToAccount();
|
||||
return false;
|
||||
});
|
||||
|
||||
$btnSubmit.click(function(evt) {
|
||||
evt.stopPropagation();
|
||||
handleUpdateProfile();
|
||||
return false;
|
||||
});
|
||||
|
||||
$('#account-profile-content-scroller').on('submit', '#account-edit-email-form', function(evt) { evt.stopPropagation(); handleUpdateProfile(); return false; } );
|
||||
$('#account-profile-content-scroller').on('click', '#account-change-avatar', function(evt) { evt.stopPropagation(); navToAvatar(); return false; } );
|
||||
}
|
||||
|
||||
function renderAccountProfile() {
|
||||
$.when(api.getUserDetail())
|
||||
$.when(api.getUserProfile())
|
||||
.done(function(userDetail) {
|
||||
recentUserDetail = userDetail;
|
||||
populateAccountProfile(userDetail);
|
||||
|
|
@ -234,7 +247,7 @@
|
|||
|
||||
function navToAccount() {
|
||||
resetForm();
|
||||
window.location = '/client#/account';
|
||||
window.location = '/client#/profile/' + context.JK.currentUserId;
|
||||
}
|
||||
|
||||
function navToAvatar() {
|
||||
|
|
|
|||
|
|
@ -8,15 +8,16 @@
|
|||
var logger = context.JK.logger;
|
||||
var EVENTS = context.JK.EVENTS;
|
||||
var api = context.JK.Rest();
|
||||
var userId;
|
||||
var user = {};
|
||||
var $screen = $('#account-profile-experience');
|
||||
var $scroller = $screen.find('#account-profile-content-scroller');
|
||||
var $instrumentSelector = null;
|
||||
var $userGenres = null;
|
||||
var profileUtils = context.JK.ProfileUtils;
|
||||
var $btnCancel = $screen.find('#account-edit-profile-cancel');
|
||||
var $btnBack = $screen.find('#account-edit-profile-back');
|
||||
var $btnSubmit = $screen.find('#account-edit-profile-submit');
|
||||
|
||||
var $instrumentSelector = $screen.find('.instrument_selector');
|
||||
var $userGenres = $screen.find('#user-genres');
|
||||
|
||||
function beforeShow(data) {
|
||||
userId = data.id;
|
||||
}
|
||||
|
||||
function afterShow(data) {
|
||||
|
|
@ -25,40 +26,36 @@
|
|||
}
|
||||
|
||||
function resetForm() {
|
||||
$scroller.find('form .error-text').remove();
|
||||
$scroller.find('form .error').removeClass("error");
|
||||
$screen.find('form .error-text').remove();
|
||||
$screen.find('form .error').removeClass("error");
|
||||
}
|
||||
|
||||
function populateAccountProfile(userDetail, instruments) {
|
||||
var template = context.JK.fillTemplate($('#template-account-profile-experience').html(), {
|
||||
user_instruments: userDetail.instruments
|
||||
});
|
||||
|
||||
$scroller.html(template);
|
||||
|
||||
$instrumentSelector = $screen.find('.instrument_selector');
|
||||
$userGenres = $screen.find('#user-genres');
|
||||
events();
|
||||
|
||||
loadGenres(userDetail.genres);
|
||||
loadGenres(profileUtils.profileGenres(userDetail.genres));
|
||||
|
||||
$instrumentSelector.empty();
|
||||
$.each(instruments, function(index, instrument) {
|
||||
var template = context.JK.fillTemplate($('#account-profile-instrument').html(), {
|
||||
checked : isUserInstrument(instrument, userDetail.instruments) ? "checked=\"checked\"" :"",
|
||||
description : instrument.description,
|
||||
id : instrument.id
|
||||
});
|
||||
$instrumentSelector.append(template)
|
||||
$instrumentSelector.append(template);
|
||||
});
|
||||
|
||||
// and fill in the proficiency for the instruments that the user can play
|
||||
if(userDetail.instruments) {
|
||||
$.each(userDetail.instruments, function(index, userInstrument) {
|
||||
$('tr[data-instrument-id="' + userInstrument.instrument_id + '"] select.proficiency_selector', $scroller).val(userInstrument.proficiency_level);
|
||||
$('tr[data-instrument-id="' + userInstrument.instrument_id + '"] select.proficiency_selector', $screen).val(userInstrument.proficiency_level);
|
||||
});
|
||||
}
|
||||
|
||||
context.JK.dropdown($('select', $scroller));
|
||||
$screen.find('select[name=skill_level]').val(userDetail.skill_level);
|
||||
$screen.find('select[name=concert_count]').val(userDetail.concert_count);
|
||||
$screen.find('select[name=studio_session_count]').val(userDetail.studio_session_count);
|
||||
|
||||
context.JK.dropdown($('select', $screen));
|
||||
}
|
||||
|
||||
function isUserInstrument(instrument, userInstruments) {
|
||||
|
|
@ -83,7 +80,7 @@
|
|||
var selected = '';
|
||||
if (selectedGenres) {
|
||||
var genreMatch = $.grep(selectedGenres, function (n, i) {
|
||||
return n.id === genre.id;
|
||||
return n.genre_id === genre.id;
|
||||
});
|
||||
if (genreMatch.length > 0) {
|
||||
selected = "checked";
|
||||
|
|
@ -116,13 +113,27 @@
|
|||
}
|
||||
|
||||
function events() {
|
||||
$screen.find('#account-edit-profile-cancel').on('click', function(evt) { evt.stopPropagation(); navigateTo('/client#/account'); return false; } );
|
||||
$screen.find('#account-edit-profile-back').on('click', function(evt) { evt.stopPropagation(); navigateTo('/client#/account/profile'); return false; } );
|
||||
$screen.find('#account-edit-profile-submit').on('click', function(evt) { evt.stopPropagation(); handleUpdateProfile(); return false; } );
|
||||
$btnCancel.click(function(evt) {
|
||||
evt.stopPropagation();
|
||||
navigateTo('/client#/profile/' + context.JK.currentUserId);
|
||||
return false;
|
||||
});
|
||||
|
||||
$btnBack.click(function(evt) {
|
||||
evt.stopPropagation();
|
||||
navigateTo('/client#/account/profile/');
|
||||
return false;
|
||||
});
|
||||
|
||||
$btnSubmit.click(function(evt) {
|
||||
evt.stopPropagation();
|
||||
handleUpdateProfile();
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
function renderExperience() {
|
||||
$.when(api.getUserDetail(), api.getInstruments())
|
||||
$.when(api.getUserProfile(), api.getInstruments())
|
||||
.done(function(userDetailResponse, instrumentsResponse) {
|
||||
var userDetail = userDetailResponse[0];
|
||||
populateAccountProfile(userDetail, instrumentsResponse[0]);
|
||||
|
|
@ -133,22 +144,21 @@
|
|||
|
||||
function navigateTo(targetLocation) {
|
||||
resetForm();
|
||||
window.location = targetLocation;
|
||||
context.location = targetLocation;
|
||||
}
|
||||
|
||||
function handleUpdateProfile() {
|
||||
resetForm();
|
||||
|
||||
var instruments = getInstrumentsValue();
|
||||
var instruments = getSelectedInstruments();
|
||||
var genres = getSelectedGenres();
|
||||
var status =
|
||||
|
||||
api.updateUser({
|
||||
instruments: instruments,
|
||||
genres: genres,
|
||||
skill_level: $scroller.find('select[name=gender]').val(),
|
||||
concert_count: $scroller.find('select[name=concert_count]').val(),
|
||||
studio_session_count: $scroller.find('select[name=studio_session_count]').val(),
|
||||
skill_level: $screen.find('select[name=skill_level]').val(),
|
||||
concert_count: $screen.find('select[name=concert_count]').val(),
|
||||
studio_session_count: $screen.find('select[name=studio_session_count]').val()
|
||||
})
|
||||
.done(postUpdateProfileSuccess)
|
||||
.fail(postUpdateProfileFailure);
|
||||
|
|
@ -167,7 +177,7 @@
|
|||
var instruments = context.JK.format_errors("musician_instruments", errors);
|
||||
|
||||
if(instruments != null) {
|
||||
instrumentSelector.closest('div.field').addClass('error').append(instruments);
|
||||
$instrumentSelector.closest('div.field').addClass('error').append(instruments);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
|
@ -175,7 +185,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
function getInstrumentsValue() {
|
||||
function getSelectedInstruments() {
|
||||
var instruments = [];
|
||||
$('input[type=checkbox]:checked', $instrumentSelector).each(function(i) {
|
||||
|
||||
|
|
@ -198,7 +208,10 @@
|
|||
'beforeShow': beforeShow,
|
||||
'afterShow': afterShow
|
||||
};
|
||||
|
||||
app.bindScreen('account/profile/experience', screenBindings);
|
||||
|
||||
events();
|
||||
}
|
||||
|
||||
this.initialize = initialize;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,283 @@
|
|||
(function(context,$) {
|
||||
|
||||
"use strict";
|
||||
|
||||
context.JK = context.JK || {};
|
||||
context.JK.AccountProfileInterests = function(app) {
|
||||
var $document = $(document);
|
||||
var logger = context.JK.logger;
|
||||
var EVENTS = context.JK.EVENTS;
|
||||
var api = context.JK.Rest();
|
||||
var ui = new context.JK.UIHelper(JK.app);
|
||||
var user = {};
|
||||
var profileUtils = context.JK.ProfileUtils;
|
||||
var masterGenreList = [];
|
||||
|
||||
var NONE_SPECIFIED = 'None specified';
|
||||
var GENRE_LIST_DELIMITER = ', ';
|
||||
|
||||
var $screen = $('#account-profile-interests');
|
||||
|
||||
var SELECT_GENRE_SELECTOR = '.select-genre';
|
||||
var GENRE_LIST_SELECTOR = '.genre-list';
|
||||
|
||||
// virtual bands
|
||||
var $virtualBandYes = $screen.find('#virtual-band-yes');
|
||||
var $virtualBandNo = $screen.find('#virtual-band-no');
|
||||
var $virtualBandGenres = $screen.find('#virtual-band-genres');
|
||||
var $btnVirtualBandGenreSelect = $virtualBandGenres.find(SELECT_GENRE_SELECTOR);
|
||||
var $virtualBandGenreList = $virtualBandGenres.find(GENRE_LIST_SELECTOR);
|
||||
var $virtualBandCommitment = $screen.find('#virtual-band-commitment');
|
||||
|
||||
// traditional bands
|
||||
var $traditionalBandYes = $screen.find('#traditional-band-yes');
|
||||
var $traditionalBandNo = $screen.find('#traditional-band-no');
|
||||
var $traditionalBandGenres = $screen.find('#traditional-band-genres');
|
||||
var $btnTraditionalBandGenreSelect = $traditionalBandGenres.find(SELECT_GENRE_SELECTOR);
|
||||
var $traditionalBandGenreList = $traditionalBandGenres.find(GENRE_LIST_SELECTOR);
|
||||
var $traditionalBandCommitment = $screen.find('#traditional-band-commitment');
|
||||
var $traditionalTouringOption = $screen.find('#traditional-band-touring');
|
||||
|
||||
// paid sessions
|
||||
var $paidSessionsYes = $screen.find('#paid-sessions-yes');
|
||||
var $paidSessionsNo = $screen.find('#paid-sessions-no');
|
||||
var $paidSessionsGenres = $screen.find('#paid-sessions-genres');
|
||||
var $btnPaidSessionsGenreSelect = $paidSessionsGenres.find(SELECT_GENRE_SELECTOR);
|
||||
var $paidSessionsGenreList = $paidSessionsGenres.find(GENRE_LIST_SELECTOR);
|
||||
var $hourlyRate = $screen.find('#hourly-rate');
|
||||
var $dailyRate = $screen.find('#daily-rate');
|
||||
|
||||
// free sessions
|
||||
var $freeSessionsYes = $screen.find('#free-sessions-yes');
|
||||
var $freeSessionsNo = $screen.find('#free-sessions-no');
|
||||
var $freeSessionsGenres = $screen.find('#free-sessions-genres');
|
||||
var $btnFreeSessionsGenreSelect = $freeSessionsGenres.find(SELECT_GENRE_SELECTOR);
|
||||
var $freeSessionsGenreList = $freeSessionsGenres.find(GENRE_LIST_SELECTOR);
|
||||
|
||||
// cowriting
|
||||
var $cowritingYes = $screen.find('#cowriting-yes');
|
||||
var $cowritingNo = $screen.find('#cowriting-no');
|
||||
var $cowritingGenres = $screen.find('#cowriting-genres');
|
||||
var $btnCowritingGenreSelect = $cowritingGenres.find(SELECT_GENRE_SELECTOR);
|
||||
var $cowritingGenreList = $cowritingGenres.find(GENRE_LIST_SELECTOR);
|
||||
var $cowritingPurpose = $screen.find('#cowriting-purpose');
|
||||
|
||||
var $btnCancel = $screen.find('#account-edit-profile-cancel');
|
||||
var $btnBack = $screen.find('#account-edit-profile-back');
|
||||
var $btnSubmit = $screen.find('#account-edit-profile-submit');
|
||||
|
||||
function beforeShow(data) {
|
||||
}
|
||||
|
||||
function afterShow(data) {
|
||||
renderInterests();
|
||||
}
|
||||
|
||||
function resetForm() {
|
||||
$screen.find('form .error-text').remove();
|
||||
$screen.find('form .error').removeClass("error");
|
||||
}
|
||||
|
||||
function populateAccountProfile(userDetail) {
|
||||
|
||||
// Column 1 - options
|
||||
if (userDetail) {
|
||||
|
||||
if (userDetail.virtual_band) {
|
||||
$virtualBandYes.iCheck('check').attr('checked', 'checked');
|
||||
}
|
||||
else {
|
||||
$virtualBandNo.iCheck('check').attr('checked', 'checked');
|
||||
}
|
||||
|
||||
if (userDetail.traditional_band) {
|
||||
$traditionalBandYes.iCheck('check').attr('checked', 'checked');
|
||||
}
|
||||
else {
|
||||
$traditionalBandNo.iCheck('check').attr('checked', 'checked');
|
||||
}
|
||||
|
||||
if (userDetail.paid_sessions) {
|
||||
$paidSessionsYes.iCheck('check').attr('checked', 'checked');
|
||||
}
|
||||
else {
|
||||
$paidSessionsNo.iCheck('check').attr('checked', 'checked');
|
||||
}
|
||||
|
||||
if (userDetail.free_sessions) {
|
||||
$freeSessionsYes.iCheck('check').attr('checked', 'checked');
|
||||
}
|
||||
else {
|
||||
$freeSessionsNo.iCheck('check').attr('checked', 'checked');
|
||||
}
|
||||
|
||||
if (userDetail.cowriting) {
|
||||
$cowritingYes.iCheck('check').attr('checked', 'checked');
|
||||
}
|
||||
else {
|
||||
$cowritingNo.iCheck('check').attr('checked', 'checked');
|
||||
}
|
||||
}
|
||||
|
||||
// Column 2 - genres
|
||||
var genres = profileUtils.virtualBandGenreList(userDetail.genres);
|
||||
$virtualBandGenreList.html(genres && genres.length > 0 ? genres : NONE_SPECIFIED);
|
||||
|
||||
genres = profileUtils.traditionalBandGenreList(userDetail.genres);
|
||||
$traditionalBandGenreList.html(genres && genres.length > 0 ? genres : NONE_SPECIFIED);
|
||||
|
||||
genres = profileUtils.paidSessionGenreList(userDetail.genres);
|
||||
$paidSessionsGenreList.html(genres && genres.length > 0 ? genres : NONE_SPECIFIED);
|
||||
|
||||
genres = profileUtils.freeSessionGenreList(userDetail.genres);
|
||||
$freeSessionsGenreList.html(genres && genres.length > 0 ? genres : NONE_SPECIFIED);
|
||||
|
||||
genres = profileUtils.cowritingGenreList(userDetail.genres);
|
||||
$cowritingGenreList.html(genres && genres.length > 0 ? genres : NONE_SPECIFIED);
|
||||
|
||||
// Column 3 - misc (play commitment, rates, cowriting purpose)
|
||||
$virtualBandCommitment.val(userDetail.virtual_band_commitment);
|
||||
context.JK.dropdown($virtualBandCommitment);
|
||||
|
||||
$traditionalBandCommitment.val(userDetail.traditional_band_commitment);
|
||||
context.JK.dropdown($traditionalBandCommitment);
|
||||
|
||||
$traditionalTouringOption.val(userDetail.traditional_band_touring ? '1' : '0');
|
||||
context.JK.dropdown($traditionalTouringOption);
|
||||
|
||||
$hourlyRate.val(userDetail.paid_sessions_hourly_rate);
|
||||
$dailyRate.val(userDetail.paid_sessions_daily_rate);
|
||||
|
||||
$cowritingPurpose.val(userDetail.cowriting_purpose);
|
||||
context.JK.dropdown($cowritingPurpose);
|
||||
}
|
||||
|
||||
function bindGenreSelector(type, $btnSelect, $genreList) {
|
||||
$btnSelect.unbind('click').click(function(evt) {
|
||||
evt.preventDefault();
|
||||
var genreText = $genreList.html();
|
||||
var genres = [];
|
||||
if (genres !== NONE_SPECIFIED) {
|
||||
genres = genreText.split(GENRE_LIST_DELIMITER);
|
||||
}
|
||||
|
||||
ui.launchGenreSelectorDialog(type, genres, function(selectedGenres) {
|
||||
$genreList.html(selectedGenres && selectedGenres.length > 0 ? selectedGenres.join(GENRE_LIST_DELIMITER) : NONE_SPECIFIED);
|
||||
});
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
function events() {
|
||||
|
||||
bindGenreSelector('virtual bands', $btnVirtualBandGenreSelect, $virtualBandGenreList);
|
||||
bindGenreSelector('traditional bands', $btnTraditionalBandGenreSelect, $traditionalBandGenreList);
|
||||
bindGenreSelector('paid sessions', $btnPaidSessionsGenreSelect, $paidSessionsGenreList);
|
||||
bindGenreSelector('free sessions', $btnFreeSessionsGenreSelect, $freeSessionsGenreList);
|
||||
bindGenreSelector('co-writing', $btnCowritingGenreSelect, $cowritingGenreList);
|
||||
|
||||
$btnCancel.click(function(evt) {
|
||||
evt.stopPropagation();
|
||||
navigateTo('/client#/profile/' + context.JK.currentUserId);
|
||||
return false;
|
||||
});
|
||||
|
||||
$btnBack.click(function(evt) {
|
||||
evt.stopPropagation();
|
||||
navigateTo('/client#/account/profile/experience');
|
||||
return false;
|
||||
});
|
||||
|
||||
$btnSubmit.click(function(evt) {
|
||||
evt.stopPropagation();
|
||||
handleUpdateProfile();
|
||||
return false;
|
||||
});
|
||||
|
||||
context.JK.dropdown($virtualBandCommitment);
|
||||
context.JK.dropdown($traditionalBandCommitment);
|
||||
context.JK.dropdown($cowritingPurpose);
|
||||
}
|
||||
|
||||
function renderInterests() {
|
||||
$.when(api.getUserProfile())
|
||||
.done(function(userDetail) {
|
||||
populateAccountProfile(userDetail);
|
||||
});
|
||||
}
|
||||
|
||||
function navigateTo(targetLocation) {
|
||||
context.location = targetLocation;
|
||||
}
|
||||
|
||||
function handleUpdateProfile() {
|
||||
resetForm();
|
||||
|
||||
api.updateUser({
|
||||
virtual_band: $screen.find('input[name=virtual_band]:checked').val(),
|
||||
virtual_band_genres: $virtualBandGenreList.html() === NONE_SPECIFIED ? [] : $virtualBandGenreList.html().split(GENRE_LIST_DELIMITER),
|
||||
virtual_band_commitment: $virtualBandCommitment.val(),
|
||||
|
||||
traditional_band: $screen.find('input[name=traditional_band]:checked').val(),
|
||||
traditional_band_genres: $traditionalBandGenreList.html() === NONE_SPECIFIED ? [] : $traditionalBandGenreList.html().split(GENRE_LIST_DELIMITER),
|
||||
traditional_band_commitment: $traditionalBandCommitment.val(),
|
||||
traditional_band_touring: $traditionalTouringOption.val(),
|
||||
|
||||
paid_sessions: $screen.find('input[name=paid_sessions]:checked').val(),
|
||||
paid_session_genres: $paidSessionsGenreList.html() === NONE_SPECIFIED ? [] : $paidSessionsGenreList.html().split(GENRE_LIST_DELIMITER),
|
||||
paid_sessions_hourly_rate: $hourlyRate.val(),
|
||||
paid_sessions_daily_rate: $dailyRate.val(),
|
||||
|
||||
free_sessions: $screen.find('input[name=free_sessions]:checked').val(),
|
||||
free_session_genre: $freeSessionsGenreList.html() === NONE_SPECIFIED ? [] : $freeSessionsGenreList.html().split(GENRE_LIST_DELIMITER),
|
||||
|
||||
cowriting: $screen.find('input[name=cowriting]:checked').val(),
|
||||
cowriting_genres: $cowritingGenreList.html() === NONE_SPECIFIED ? [] : $cowritingGenreList.html().split(GENRE_LIST_DELIMITER),
|
||||
cowriting_purpose: $cowritingPurpose.val()
|
||||
})
|
||||
.done(postUpdateProfileSuccess)
|
||||
.fail(postUpdateProfileFailure);
|
||||
}
|
||||
|
||||
function postUpdateProfileSuccess(response) {
|
||||
$document.triggerHandler(EVENTS.USER_UPDATED, response);
|
||||
context.location = "/client#/account/profile/samples";
|
||||
}
|
||||
|
||||
function postUpdateProfileFailure(xhr, textStatus, errorMessage) {
|
||||
|
||||
var errors = JSON.parse(xhr.responseText)
|
||||
|
||||
if(xhr.status == 422) {
|
||||
|
||||
}
|
||||
else {
|
||||
app.ajaxError(xhr, textStatus, errorMessage)
|
||||
}
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
var screenBindings = {
|
||||
'beforeShow': beforeShow,
|
||||
'afterShow': afterShow
|
||||
};
|
||||
|
||||
app.bindScreen('account/profile/interests', screenBindings);
|
||||
|
||||
events();
|
||||
|
||||
$screen.find('.interest-options').iCheck({
|
||||
checkboxClass: 'icheckbox_minimal',
|
||||
radioClass: 'iradio_minimal',
|
||||
inheritClass: true
|
||||
});
|
||||
}
|
||||
|
||||
this.initialize = initialize;
|
||||
this.beforeShow = beforeShow;
|
||||
this.afterShow = afterShow;
|
||||
return this;
|
||||
};
|
||||
|
||||
})(window,jQuery);
|
||||
|
|
@ -0,0 +1,300 @@
|
|||
(function(context,$) {
|
||||
|
||||
"use strict";
|
||||
|
||||
context.JK = context.JK || {};
|
||||
context.JK.AccountProfileSamples = function(app) {
|
||||
var $document = $(document);
|
||||
var logger = context.JK.logger;
|
||||
var EVENTS = context.JK.EVENTS;
|
||||
var api = context.JK.Rest();
|
||||
var ui = new context.JK.UIHelper(JK.app);
|
||||
var user = {};
|
||||
var profileUtils = context.JK.ProfileUtils;
|
||||
|
||||
var $screen = $('#account-profile-samples');
|
||||
|
||||
// online presences
|
||||
var $website = $screen.find('#website');
|
||||
var $soundCloudUsername = $screen.find('#soundcloud-username');
|
||||
var $reverbNationUsername = $screen.find('#reverbnation-username');
|
||||
var $bandCampUsername = $screen.find('#bandcamp-username');
|
||||
var $fandalismUsername = $screen.find('#fandalism-username');
|
||||
var $youTubeUsername = $screen.find('#youtube-username');
|
||||
var $facebookUsername = $screen.find('#facebook-username');
|
||||
var $twitterUsername = $screen.find('#twitter-username');
|
||||
|
||||
// performance samples
|
||||
var $soundCloudRecordingUrl = $screen.find('#soundcloud-recording');
|
||||
var $youTubeVideoUrl = $screen.find('#youtube-video');
|
||||
|
||||
var $jamkazamSampleList = $screen.find('.samples.jamkazam');
|
||||
var $soundCloudSampleList = $screen.find('.samples.soundcloud');
|
||||
var $youTubeSampleList = $screen.find('.samples.youtube');
|
||||
|
||||
// buttons
|
||||
var $btnAddJkRecording = $screen.find('#btn-add-jk-recording');
|
||||
var $btnAddSoundCloudRecording = $screen.find('#btn-add-soundcloud-recording');
|
||||
var $btnAddYouTubeVideo = $screen.find('#btn-add-youtube-video');
|
||||
|
||||
var $btnCancel = $screen.find('#account-edit-profile-cancel');
|
||||
var $btnBack = $screen.find('#account-edit-profile-back');
|
||||
var $btnSubmit = $screen.find('#account-edit-profile-submit');
|
||||
|
||||
function beforeShow(data) {
|
||||
}
|
||||
|
||||
function afterShow(data) {
|
||||
$.when(api.getUserProfile())
|
||||
.done(function(userDetail) {
|
||||
renderPresence(userDetail);
|
||||
renderSamples(userDetail);
|
||||
});
|
||||
}
|
||||
|
||||
function renderPresence(user) {
|
||||
$website.val(user.website);
|
||||
|
||||
// SoundCloud
|
||||
var presences = profileUtils.soundCloudPresences(user.online_presences);
|
||||
if (presences && presences.length > 0) {
|
||||
$soundCloudUsername.val(presences[0].username);
|
||||
}
|
||||
|
||||
// ReverbNation
|
||||
presences = profileUtils.reverbNationPresences(user.online_presences);
|
||||
if (presences && presences.length > 0) {
|
||||
$reverbNationUsername.val(presences[0].username);
|
||||
}
|
||||
|
||||
// Bandcamp
|
||||
presences = profileUtils.bandCampPresences(user.online_presences);
|
||||
if (presences && presences.length > 0) {
|
||||
$bandCampUsername.val(presences[0].username);
|
||||
}
|
||||
|
||||
// Fandalism
|
||||
presences = profileUtils.fandalismPresences(user.online_presences);
|
||||
if (presences && presences.length > 0) {
|
||||
$fandalismUsername.val(presences[0].username);
|
||||
}
|
||||
|
||||
// YouTube
|
||||
presences = profileUtils.youTubePresences(user.online_presences);
|
||||
if (presences && presences.length > 0) {
|
||||
$youTubeUsername.val(presences[0].username);
|
||||
}
|
||||
|
||||
// Facebook
|
||||
presences = profileUtils.facebookPresences(user.online_presences);
|
||||
if (presences && presences.length > 0) {
|
||||
$facebookUsername.val(presences[0].username);
|
||||
}
|
||||
|
||||
// Twitter
|
||||
presences = profileUtils.twitterPresences(user.online_presences);
|
||||
if (presences && presences.length > 0) {
|
||||
$twitterUsername.val(presences[0].username);
|
||||
}
|
||||
}
|
||||
|
||||
function renderSamples(user) {
|
||||
|
||||
// JamKazam recordings
|
||||
var samples = profileUtils.jamkazamSamples(user.performance_samples);
|
||||
if (samples) {
|
||||
$.each(samples, function(index, val) {
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
// SoundCloud recordings
|
||||
samples = profileUtils.soundCloudSamples(user.performance_samples);
|
||||
if (samples) {
|
||||
$.each(samples, function(index, val) {
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
// YouTube videos
|
||||
samples = profileUtils.youTubeSamples(user.performance_samples);
|
||||
if (samples) {
|
||||
$.each(samples, function(index, val) {
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function events() {
|
||||
|
||||
$website.blur(function(evt) {
|
||||
evt.preventDefault();
|
||||
// TODO: validate website
|
||||
});
|
||||
|
||||
$soundCloudUsername.blur(function(evt) {
|
||||
evt.preventDefault();
|
||||
// TODO: validate SoundCloud username
|
||||
});
|
||||
|
||||
$reverbNationUsername.blur(function(evt) {
|
||||
evt.preventDefault();
|
||||
// TODO: validate ReverbNation username
|
||||
});
|
||||
|
||||
$bandCampUsername.blur(function(evt) {
|
||||
evt.preventDefault();
|
||||
// TODO: validate Bandcamp username
|
||||
});
|
||||
|
||||
$fandalismUsername.blur(function(evt) {
|
||||
evt.preventDefault();
|
||||
// TODO: validate Fandalism username
|
||||
});
|
||||
|
||||
$youTubeUsername.blur(function(evt) {
|
||||
evt.preventDefault();
|
||||
// TODO: validate YouTube username
|
||||
});
|
||||
|
||||
$facebookUsername.blur(function(evt) {
|
||||
evt.preventDefault();
|
||||
// TODO: validate Facebook username
|
||||
});
|
||||
|
||||
$twitterUsername.blur(function(evt) {
|
||||
evt.preventDefault();
|
||||
// TODO: validate Twitter username
|
||||
});
|
||||
|
||||
|
||||
// buttons
|
||||
$btnAddJkRecording.click(function(evt) {
|
||||
evt.preventDefault();
|
||||
ui.launchRecordingSelectorDialog('', function(selectedRecordings) {
|
||||
|
||||
});
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
$btnAddSoundCloudRecording.click(function(evt) {
|
||||
var url = $soundCloudRecordingUrl.val();
|
||||
if (url.length > 0) {
|
||||
if (extractSoundCloudUrlParts(url)) {
|
||||
// add to list
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$btnAddYouTubeVideo.click(function(evt) {
|
||||
var url = $youTubeVideoUrl.val();
|
||||
if (url.length) {
|
||||
if (extractYouTubeUrlParts(url)) {
|
||||
// add to list
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$btnCancel.click(function(evt) {
|
||||
evt.stopPropagation();
|
||||
navigateTo('/client#/profile/' + context.JK.currentUserId);
|
||||
return false;
|
||||
});
|
||||
|
||||
$btnBack.click(function(evt) {
|
||||
evt.stopPropagation();
|
||||
navigateTo('/client#/account/profile/interests');
|
||||
return false;
|
||||
});
|
||||
|
||||
$btnSubmit.click(function(evt) {
|
||||
$document.triggerHandler(EVENTS.USER_UPDATED, response);
|
||||
|
||||
handleUpdateProfile();
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
function navigateTo(targetLocation) {
|
||||
context.location = targetLocation;
|
||||
}
|
||||
|
||||
function addOnlinePresence(presenceArray, username, type) {
|
||||
if ($.trim($soundCloudUsername.val()).length > 0) {
|
||||
presenceArray.push({
|
||||
service_type: type,
|
||||
username: username
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function addPerformanceSamples(sampleArray, $samplesSelector, type) {
|
||||
var sampleTable = $samplesSelector.find('table');
|
||||
// loop over rows, extracting service id, description, and url
|
||||
}
|
||||
|
||||
function handleUpdateProfile() {
|
||||
|
||||
// extract online presences
|
||||
var op = [];
|
||||
var presenceTypes = profileUtils.ONLINE_PRESENCE_TYPES;
|
||||
addOnlinePresence(op, $soundCloudUsername.val(), presenceTypes.SOUNDCLOUD.description);
|
||||
addOnlinePresence(op, $reverbNationUsername.val(), presenceTypes.REVERBNATION.description);
|
||||
addOnlinePresence(op, $bandCampUsername.val(), presenceTypes.BANDCAMP.description);
|
||||
addOnlinePresence(op, $fandalismUsername.val(), presenceTypes.FANDALISM.description);
|
||||
addOnlinePresence(op, $youTubeUsername.val(), presenceTypes.YOUTUBE.description);
|
||||
addOnlinePresence(op, $facebookUsername.val(), presenceTypes.FACEBOOK.description);
|
||||
addOnlinePresence(op, $twitterUsername.val(), presenceTypes.TWITTER.description);
|
||||
|
||||
// extract performance samples
|
||||
var ps = [];
|
||||
var performanceSampleTypes = profileUtils.SAMPLE_TYPES;
|
||||
addPerformanceSamples(ps, $jamkazamSampleList, performanceSampleTypes.JAMKAZAM);
|
||||
addPerformanceSamples(ps, $soundCloudSampleList, performanceSampleTypes.SOUNDCLOUD);
|
||||
addPerformanceSamples(ps, $youTubeSampleList, performanceSampleTypes.YOUTUBE);
|
||||
|
||||
// api.updateUser({
|
||||
// website: $website.val(),
|
||||
// online_presences: op,
|
||||
// performance_samples: ps
|
||||
// })
|
||||
// .done(postUpdateProfileSuccess)
|
||||
// .fail(postUpdateProfileFailure);
|
||||
}
|
||||
|
||||
function postUpdateProfileSuccess(response) {
|
||||
$document.triggerHandler(EVENTS.USER_UPDATED, response);
|
||||
context.location = "/client#/profile/" + context.JK.currentUserId;
|
||||
}
|
||||
|
||||
function postUpdateProfileFailure(xhr, textStatus, errorMessage) {
|
||||
|
||||
var errors = JSON.parse(xhr.responseText)
|
||||
|
||||
if(xhr.status == 422) {
|
||||
|
||||
}
|
||||
else {
|
||||
app.ajaxError(xhr, textStatus, errorMessage)
|
||||
}
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
var screenBindings = {
|
||||
'beforeShow': beforeShow,
|
||||
'afterShow': afterShow
|
||||
};
|
||||
|
||||
app.bindScreen('account/profile/samples', screenBindings);
|
||||
|
||||
events();
|
||||
}
|
||||
|
||||
this.initialize = initialize;
|
||||
this.beforeShow = beforeShow;
|
||||
this.afterShow = afterShow;
|
||||
return this;
|
||||
};
|
||||
|
||||
})(window,jQuery);
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
(function(context,$) {
|
||||
|
||||
"use strict";
|
||||
context.JK = context.JK || {};
|
||||
context.JK.GenreSelectorDialog = function(app, type, genres, callback) {
|
||||
var logger = context.JK.logger;
|
||||
var rest = context.JK.Rest();
|
||||
var $dialog = null;
|
||||
var dialogId = 'genre-selector-dialog';
|
||||
var $screen = $('#' + dialogId);
|
||||
var $btnSelect = $screen.find(".btn-select-genres");
|
||||
var $instructions = $screen.find('#instructions');
|
||||
var $genres = $screen.find('.genres');
|
||||
var GENRES_PER_COLUMN = 12;
|
||||
|
||||
function beforeShow(data) {
|
||||
}
|
||||
|
||||
function afterShow(data) {
|
||||
var genreList = context.JK.genres;
|
||||
|
||||
$genres.empty();
|
||||
|
||||
if (genreList) {
|
||||
var columns = genreList.length / GENRES_PER_COLUMN;
|
||||
columns = Math.floor((genreList.length % GENRES_PER_COLUMN) === 0 ? columns : columns + 1);
|
||||
|
||||
var columnWidthPct = 100/columns;
|
||||
|
||||
$.each(genreList, function(index, val) {
|
||||
if (index === 0 || index % GENRES_PER_COLUMN === 0) {
|
||||
$genres.append('<div class="left" style="width:"' + columnWidthPct + '%;"><table>');
|
||||
}
|
||||
|
||||
$genres.append('<tr>');
|
||||
var checked = '';
|
||||
if (genres && $.inArray(val.id, genres) > -1) {
|
||||
checked = 'checked';
|
||||
}
|
||||
|
||||
$genres.append('<td><input type="checkbox" value="' + val.id + '" ' + checked + ' />' + val.description + '</td>');
|
||||
$genres.append('</tr>');
|
||||
|
||||
if (index === genreList.length-1 || (index+1) % GENRES_PER_COLUMN === 0) {
|
||||
$genres.append('</table></div>')
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function afterHide() {
|
||||
}
|
||||
|
||||
function showDialog() {
|
||||
return app.layout.showDialog(dialogId);
|
||||
}
|
||||
|
||||
function events() {
|
||||
$btnSelect.click(function(evt) {
|
||||
evt.preventDefault();
|
||||
var selectedGenres = [];
|
||||
$genres.find('input[type=checkbox]:checked').each(function(index) {
|
||||
selectedGenres.push($(this).val());
|
||||
});
|
||||
|
||||
if (callback) {
|
||||
callback(selectedGenres);
|
||||
}
|
||||
|
||||
app.layout.closeDialog(dialogId);
|
||||
|
||||
return false;
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
var dialogBindings = {
|
||||
'beforeShow' : beforeShow,
|
||||
'afterShow' : afterShow,
|
||||
'afterHide': afterHide
|
||||
};
|
||||
|
||||
app.bindDialog(dialogId, dialogBindings);
|
||||
|
||||
$instructions.html('Select one or more genres for ' + type + ':');
|
||||
|
||||
events();
|
||||
}
|
||||
|
||||
this.initialize = initialize;
|
||||
this.showDialog = showDialog;
|
||||
}
|
||||
|
||||
return this;
|
||||
})(window,jQuery);
|
||||
|
|
@ -58,7 +58,8 @@
|
|||
options.jamTrackId = jamTrack.id;
|
||||
options.name = jamTrack.name;
|
||||
options.artist = jamTrack.original_artist;
|
||||
options.downloaded = 'Yes'
|
||||
var detail = context.jamClient.JamTrackGetTrackDetail(jamTrack.id) || {}
|
||||
options.downloaded = detail.key_state == 'ready' ? 'Yes' : 'No'
|
||||
|
||||
var $tr = $(context._.template($templateOpenJamTrackRow.html(), options, { variable: 'data' }));
|
||||
$tr.data('server-model', jamTrack);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,68 @@
|
|||
(function(context,$) {
|
||||
|
||||
"use strict";
|
||||
context.JK = context.JK || {};
|
||||
context.JK.RecordingSelectorDialog = function(app, recordings, selectedRecordings, callback) {
|
||||
var logger = context.JK.logger;
|
||||
var rest = context.JK.Rest();
|
||||
var $dialog = null;
|
||||
var dialogId = 'recording-selector-dialog';
|
||||
var $screen = $('#' + dialogId);
|
||||
var $btnSelect = $screen.find(".btn-select-recordings");
|
||||
var $instructions = $screen.find('#instructions');
|
||||
var $recordings = $screen.find('.recordings');
|
||||
|
||||
function beforeShow(data) {
|
||||
}
|
||||
|
||||
function afterShow(data) {
|
||||
|
||||
$recordings.empty();
|
||||
}
|
||||
|
||||
function afterHide() {
|
||||
}
|
||||
|
||||
function showDialog() {
|
||||
return app.layout.showDialog(dialogId);
|
||||
}
|
||||
|
||||
function events() {
|
||||
$btnSelect.click(function(evt) {
|
||||
evt.preventDefault();
|
||||
var selectedRecordings = [];
|
||||
$recordings.find('input[type=checkbox]:checked').each(function(index) {
|
||||
selectedRecordings.push($(this).val());
|
||||
});
|
||||
|
||||
if (callback) {
|
||||
callback(selectedRecordings);
|
||||
}
|
||||
|
||||
app.layout.closeDialog(dialogId);
|
||||
|
||||
return false;
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
var dialogBindings = {
|
||||
'beforeShow' : beforeShow,
|
||||
'afterShow' : afterShow,
|
||||
'afterHide': afterHide
|
||||
};
|
||||
|
||||
app.bindDialog(dialogId, dialogBindings);
|
||||
|
||||
$instructions.html('Select one or more recordings.');
|
||||
|
||||
events();
|
||||
}
|
||||
|
||||
this.initialize = initialize;
|
||||
this.showDialog = showDialog;
|
||||
}
|
||||
|
||||
return this;
|
||||
})(window,jQuery);
|
||||
|
|
@ -74,6 +74,9 @@
|
|||
|
||||
var playState = PlayStateNone; // tracks if the stream is actually playing
|
||||
|
||||
var CANNOT_BROADCAST_TITLE = 'Unable to Broadcast Session';
|
||||
var CANNOT_BROADCAST_MSG = 'This session cannot be broadcasted. The session organizer may have configured it to be private.';
|
||||
|
||||
function play(e) {
|
||||
if(e) {
|
||||
e.preventDefault();
|
||||
|
|
@ -407,17 +410,21 @@
|
|||
sessionInfo = response;
|
||||
})
|
||||
.fail(function(jqXHR) {
|
||||
if(jqXHR.status == 404 || jqXHR.status == 403) {
|
||||
if(jqXHR.status == 404) {
|
||||
transition(PlayStateSessionOver);
|
||||
destroy();
|
||||
}
|
||||
else if (jqXHR.status == 403) {
|
||||
logger.debug("session is private");
|
||||
context.JK.app.notify({"title": CANNOT_BROADCAST_TITLE, "text": CANNOT_BROADCAST_MSG});
|
||||
}
|
||||
else if(jqXHR.status >= 500 && jqXHR.status <= 599){
|
||||
transition(PlayStateServerError);
|
||||
}
|
||||
else {
|
||||
transition(PlayStateNetworkError);
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
function triggerStateChange() {
|
||||
|
|
@ -702,28 +709,31 @@
|
|||
}
|
||||
|
||||
function openBubble() {
|
||||
checkServer().done(function(response) {
|
||||
checkServer()
|
||||
.done(function(response) {
|
||||
|
||||
var mountId = sessionInfo.mount ? sessionInfo.mount.id : null;
|
||||
var mountId = sessionInfo.mount ? sessionInfo.mount.id : null;
|
||||
|
||||
if(mountId) {
|
||||
rest.getMount({id: mountId})
|
||||
.done(function (mount) {
|
||||
mountInfo = mount;
|
||||
$parent.data('mount-id', mountId);
|
||||
context.JK.SubscriptionUtils.subscribe('mount', mountId).on(context.JK.EVENTS.SUBSCRIBE_NOTIFICATION, onDetailEvent);
|
||||
$parent.btOn();
|
||||
})
|
||||
.fail(context.JK.app.ajaxError)
|
||||
}
|
||||
else {
|
||||
mountInfo = null;
|
||||
destroy();
|
||||
context.JK.app.notify({"title": "Unable to Broadcast Session", "text": "This session cannot be broadcasted. The session organizer may have configured it to be private."});
|
||||
}
|
||||
})
|
||||
.fail(function() {
|
||||
logger.debug("session is over")
|
||||
if(mountId) {
|
||||
rest.getMount({id: mountId})
|
||||
.done(function (mount) {
|
||||
mountInfo = mount;
|
||||
$parent.data('mount-id', mountId);
|
||||
context.JK.SubscriptionUtils.subscribe('mount', mountId).on(context.JK.EVENTS.SUBSCRIBE_NOTIFICATION, onDetailEvent);
|
||||
$parent.btOn();
|
||||
})
|
||||
.fail(context.JK.app.ajaxError)
|
||||
}
|
||||
else {
|
||||
mountInfo = null;
|
||||
destroy();
|
||||
context.JK.app.notify({"title": CANNOT_BROADCAST_TITLE, "text": CANNOT_BROADCAST_MSG});
|
||||
}
|
||||
})
|
||||
.fail(function(response) {
|
||||
if (response.status == 404) {
|
||||
logger.debug("session is over");
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -42,9 +42,16 @@
|
|||
var $li = $(this);
|
||||
var playbackMode = $li.attr('data-playback-option');
|
||||
|
||||
value = playbackMode;
|
||||
close();
|
||||
$parent.triggerHandler(context.JK.EVENTS.METRONOME_PLAYBACK_MODE_SELECTED, {playbackMode: playbackMode});
|
||||
if(playbackMode) {
|
||||
value = playbackMode;
|
||||
close();
|
||||
$parent.triggerHandler(context.JK.EVENTS.METRONOME_PLAYBACK_MODE_SELECTED, {playbackMode: playbackMode});
|
||||
}
|
||||
else {
|
||||
// if no playback mode, then this must be an attempt to open metronome window
|
||||
close();
|
||||
context.jamClient.SessionShowMetronomeGui();
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
|
|
@ -69,7 +76,7 @@
|
|||
cssClass: 'metronome-playback-mode-selector-popup',
|
||||
spikeGirth:0,
|
||||
spikeLength:0,
|
||||
width:160,
|
||||
width:180,
|
||||
closeWhenOthersOpen: true,
|
||||
offsetParent: $parent.offsetParent(),
|
||||
positions:['top'],
|
||||
|
|
|
|||
|
|
@ -215,14 +215,6 @@
|
|||
top: childLayout.top,
|
||||
left: childLayout.left
|
||||
}, opts.animationDuration);
|
||||
|
||||
if($(this).is('.feed')) {
|
||||
$('#jamblaster-notice').animate({
|
||||
width: childLayout.width,
|
||||
bottom: '102%',
|
||||
left: childLayout.left
|
||||
}, opts.animationDuration)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
var TEST_TIMEOUT_CALLBACK = 'JK.HandleNetworkTestTimeout';
|
||||
|
||||
var $startNetworkTestBtn = null;
|
||||
var $foreverNetworkTestBtn = null;
|
||||
var $testResults = null;
|
||||
var $testScore = null;
|
||||
var $testText = null;
|
||||
|
|
@ -51,6 +52,8 @@
|
|||
var operatingSystem = null;
|
||||
var PRIME_PUMP_TIME = 1;
|
||||
|
||||
var forever = false;
|
||||
|
||||
// these try to make it such that we only pass a NetworkTest Pass/Failed one time in a new user flow
|
||||
var trackedPass = false;
|
||||
var lastNetworkFailure = null;
|
||||
|
|
@ -313,6 +316,9 @@
|
|||
|
||||
if (success) {
|
||||
$self.triggerHandler(NETWORK_TEST_DONE)
|
||||
if(forever) {
|
||||
prepareNetworkTest();
|
||||
}
|
||||
}
|
||||
else {
|
||||
$self.triggerHandler(NETWORK_TEST_FAIL)
|
||||
|
|
@ -875,6 +881,7 @@
|
|||
inGearWizard = _inGearWizard;
|
||||
|
||||
$startNetworkTestBtn = $step.find('.start-network-test');
|
||||
$foreverNetworkTestBtn = $step.find('.forever-network-test')
|
||||
|
||||
if ($startNetworkTestBtn.length == 0) throw 'no start network test button found in network-test'
|
||||
|
||||
|
|
@ -889,8 +896,16 @@
|
|||
$subscore = $step.find('.subscore');
|
||||
$watchVideo = $step.find('.watch-video');
|
||||
$startNetworkTestBtn.on('click', function () {
|
||||
forever = false;
|
||||
prepareNetworkTest();
|
||||
});
|
||||
if(context.JK.currentUserAdmin) {
|
||||
$foreverNetworkTestBtn.on('click', function() {
|
||||
forever = true;
|
||||
prepareNetworkTest();
|
||||
}).show();
|
||||
}
|
||||
|
||||
operatingSystem = context.JK.GetOSAsString();
|
||||
|
||||
initializeVideoWatchButton();
|
||||
|
|
|
|||
|
|
@ -680,13 +680,13 @@
|
|||
$paidGigSection.show();
|
||||
|
||||
var genreList = profileUtils.paidSessionGenreList(user.genres);
|
||||
$paidGigDetails.find("ul li:nth-child(1)").append(genreList.length > 0 ? genreList : NOT_SPECIFIED_TEXT);
|
||||
$paidGigDetails.find("ul li:nth-child(1)").html('Genre(s): ' + (genreList.length > 0 ? genreList : NOT_SPECIFIED_TEXT));
|
||||
|
||||
var hourlyRate = user.paid_sessions_hourly_rate;
|
||||
$paidGigDetails.find("ul li:nth-child(2)").append(hourlyRate ? hourlyRate : NOT_SPECIFIED_TEXT);
|
||||
$paidGigDetails.find("ul li:nth-child(2)").html('Hourly rate = ' + (hourlyRate ? hourlyRate : NOT_SPECIFIED_TEXT));
|
||||
|
||||
var dailyRate = user.paid_sessions_daily_rate;
|
||||
$paidGigDetails.find("ul li:nth-child(3)").append(dailyRate ? dailyRate : NOT_SPECIFIED_TEXT);
|
||||
$paidGigDetails.find("ul li:nth-child(3)").html('Day rate = ' + (dailyRate ? dailyRate : NOT_SPECIFIED_TEXT));
|
||||
}
|
||||
else {
|
||||
$paidGigSection.hide();
|
||||
|
|
@ -697,7 +697,7 @@
|
|||
$freeGigSection.show();
|
||||
|
||||
var genreList = profileUtils.freeSessionGenreList(user.genres);
|
||||
$freeGigDetails.find("ul li:nth-child(1)").append(genreList.length > 0 ? genreList : NOT_SPECIFIED_TEXT);
|
||||
$freeGigDetails.find("ul li:nth-child(1)").html('Genre(s): ' + (genreList.length > 0 ? genreList : NOT_SPECIFIED_TEXT));
|
||||
}
|
||||
else {
|
||||
$freeGigSection.hide();
|
||||
|
|
@ -708,10 +708,10 @@
|
|||
$cowritingSection.show();
|
||||
|
||||
var genreList = profileUtils.cowritingGenreList(user.genres);
|
||||
$cowritingDetails.find("ul li:nth-child(1)").append(genreList.length > 0 ? genreList : NOT_SPECIFIED_TEXT);
|
||||
$cowritingDetails.find("ul li:nth-child(1)").html('Genre(s): ' + (genreList.length > 0 ? genreList : NOT_SPECIFIED_TEXT));
|
||||
|
||||
var purpose = user.cowriting_purpose;
|
||||
$cowritingDetails.find("ul li:nth-child(2)").append(purpose ? profileUtils.cowritingPurposeMap[purpose] : NOT_SPECIFIED_TEXT);
|
||||
$cowritingDetails.find("ul li:nth-child(2)").html('Purpose: ' + (purpose ? profileUtils.cowritingPurposeMap[purpose] : NOT_SPECIFIED_TEXT));
|
||||
}
|
||||
else {
|
||||
$cowritingSection.hide();
|
||||
|
|
@ -722,14 +722,14 @@
|
|||
$traditionalBandSection.show();
|
||||
|
||||
var genreList = profileUtils.traditionalBandGenreList(user.genres);
|
||||
$traditionalBandDetails.find("ul li:nth-child(1)").append(genreList.length > 0 ? genreList : NOT_SPECIFIED_TEXT);
|
||||
$traditionalBandDetails.find("ul li:nth-child(1)").html('Genre(s): ' + (genreList.length > 0 ? genreList : NOT_SPECIFIED_TEXT));
|
||||
|
||||
var commitment = user.traditional_band_commitment;
|
||||
$traditionalBandDetails.find("ul li:nth-child(2)").append(commitment ? profileUtils.bandCommitmentMap[commitment] : NOT_SPECIFIED_TEXT);
|
||||
$traditionalBandDetails.find("ul li:nth-child(2)").html('Commitment: ' + (commitment ? profileUtils.bandCommitmentMap[commitment] : NOT_SPECIFIED_TEXT));
|
||||
|
||||
var canTour = user.traditional_band_touring;
|
||||
var canTourResponse = canTour ? "Yes" : (canTour === false ? "No" : NOT_SPECIFIED_TEXT);
|
||||
$traditionalBandDetails.find("ul li:nth-child(3)").append(canTourResponse);
|
||||
$traditionalBandDetails.find("ul li:nth-child(3)").html('Touring: ' + canTourResponse);
|
||||
}
|
||||
else {
|
||||
$traditionalBandSection.hide();
|
||||
|
|
@ -740,10 +740,10 @@
|
|||
$virtualBandSection.show();
|
||||
|
||||
var genreList = profileUtils.virtualBandGenreList(user.genres);
|
||||
$virtualBandDetails.find("ul li:nth-child(1)").append(genreList.length > 0 ? genreList : NOT_SPECIFIED_TEXT);
|
||||
$virtualBandDetails.find("ul li:nth-child(1)").html('Genre(s): ' + (genreList.length > 0 ? genreList : NOT_SPECIFIED_TEXT));
|
||||
|
||||
var commitment = user.virtual_band_commitment;
|
||||
$virtualBandDetails.find("ul li:nth-child(2)").append(commitment ? profileUtils.bandCommitmentMap[commitment] : NOT_SPECIFIED_TEXT);
|
||||
$virtualBandDetails.find("ul li:nth-child(2)").html('Commitment: ' + (commitment ? profileUtils.bandCommitmentMap[commitment] : NOT_SPECIFIED_TEXT));
|
||||
}
|
||||
else {
|
||||
$virtualBandSection.hide();
|
||||
|
|
|
|||
|
|
@ -17,13 +17,14 @@
|
|||
var FREE_SESSION_GENRE_TYPE = 'free_sessions';
|
||||
var COWRITING_GENRE_TYPE = 'cowriting';
|
||||
|
||||
// performance samples
|
||||
// performance sample types
|
||||
var SAMPLE_TYPES = {
|
||||
JAMKAZAM: {description: "jamkazam"},
|
||||
SOUNDCLOUD: {description: "soundcloud"},
|
||||
YOUTUBE: {description: "youtube"}
|
||||
};
|
||||
|
||||
// online presence types
|
||||
var ONLINE_PRESENCE_TYPES = {
|
||||
SOUNDCLOUD: {description: "soundcloud"},
|
||||
REVERBNATION: {description: "reverbnation"},
|
||||
|
|
@ -79,7 +80,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
return list.length > 0;
|
||||
return list;
|
||||
}
|
||||
|
||||
// profile genres
|
||||
|
|
@ -98,9 +99,12 @@
|
|||
|
||||
// virtual band genres
|
||||
profileUtils.virtualBandGenres = function(genres) {
|
||||
var matches = $.grep(genres, function(g) {
|
||||
return g.player_type === USER_TYPE && g.genre_type === VIRTUAL_BAND_GENRE_TYPE;
|
||||
});
|
||||
var matches = [];
|
||||
if (genres) {
|
||||
matches = $.grep(genres, function(g) {
|
||||
return g.player_type === USER_TYPE && g.genre_type === VIRTUAL_BAND_GENRE_TYPE;
|
||||
});
|
||||
}
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
|
@ -112,9 +116,12 @@
|
|||
|
||||
// traditional band genres
|
||||
profileUtils.traditionalBandGenres = function(genres) {
|
||||
var matches = $.grep(genres, function(g) {
|
||||
return g.player_type === USER_TYPE && g.genre_type === TRADITIONAL_BAND_GENRE_TYPE;
|
||||
});
|
||||
var matches = [];
|
||||
if (genres) {
|
||||
matches = $.grep(genres, function(g) {
|
||||
return g.player_type === USER_TYPE && g.genre_type === TRADITIONAL_BAND_GENRE_TYPE;
|
||||
});
|
||||
}
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
|
@ -126,9 +133,12 @@
|
|||
|
||||
// paid session genres
|
||||
profileUtils.paidSessionGenres = function(genres) {
|
||||
var matches = $.grep(genres, function(g) {
|
||||
return g.player_type === USER_TYPE && g.genre_type === PAID_SESSION_GENRE_TYPE;
|
||||
});
|
||||
var matches = [];
|
||||
if (genres) {
|
||||
matches = $.grep(genres, function(g) {
|
||||
return g.player_type === USER_TYPE && g.genre_type === PAID_SESSION_GENRE_TYPE;
|
||||
});
|
||||
}
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
|
@ -140,9 +150,12 @@
|
|||
|
||||
// free session genres
|
||||
profileUtils.freeSessionGenres = function(genres) {
|
||||
var matches = $.grep(genres, function(g) {
|
||||
return g.player_type === USER_TYPE && g.genre_type === FREE_SESSION_GENRE_TYPE;
|
||||
});
|
||||
var matches = [];
|
||||
if (genres) {
|
||||
matches = $.grep(genres, function(g) {
|
||||
return g.player_type === USER_TYPE && g.genre_type === FREE_SESSION_GENRE_TYPE;
|
||||
});
|
||||
}
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
|
@ -154,9 +167,12 @@
|
|||
|
||||
// cowriting genres
|
||||
profileUtils.cowritingGenres = function(genres) {
|
||||
var matches = $.grep(genres, function(g) {
|
||||
return g.player_type === USER_TYPE && g.genre_type === COWRITING_GENRE_TYPE;
|
||||
});
|
||||
var matches = [];
|
||||
if (genres) {
|
||||
matches = $.grep(genres, function(g) {
|
||||
return g.player_type === USER_TYPE && g.genre_type === COWRITING_GENRE_TYPE;
|
||||
});
|
||||
}
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -114,8 +114,9 @@
|
|||
var $openBackingTrack = null;
|
||||
var $metronomePlaybackSelect = null;
|
||||
var $metronomePlaybackHelp = null;
|
||||
var $templatePendingMetronome = null;
|
||||
var mediaTrackGroups = [ChannelGroupIds.MediaTrackGroup, ChannelGroupIds.JamTrackGroup, ChannelGroupIds.MetronomeGroup];
|
||||
var muteBothMasterAndPersonalGroups = [ChannelGroupIds.MediaTrackGroup, ChannelGroupIds.JamTrackGroup, ChannelGroupIds.MetronomeGroup];
|
||||
var muteBothMasterAndPersonalGroups = [ChannelGroupIds.AudioInputMusicGroup, ChannelGroupIds.MediaTrackGroup, ChannelGroupIds.JamTrackGroup, ChannelGroupIds.MetronomeGroup];
|
||||
|
||||
var rest = context.JK.Rest();
|
||||
var RENDER_SESSION_DELAY = 750; // When I need to render a session, I have to wait a bit for the mixers to be there.
|
||||
|
|
@ -234,12 +235,8 @@
|
|||
promptLeave = false;
|
||||
window.location = '/client#/home'
|
||||
});
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
|
||||
}
|
||||
|
||||
function notifyWithUserInfo(title , text, clientId) {
|
||||
|
|
@ -495,7 +492,7 @@
|
|||
}
|
||||
|
||||
function checkJamTrackTransition(currentSession) {
|
||||
// handle jam tracks
|
||||
// handle jam tracks
|
||||
if (jamTrack == null && (currentSession && currentSession.jam_track != null)) {
|
||||
playbackControls.startMonitor(context.JK.PLAYBACK_MONITOR_MODE.JAMTRACK);
|
||||
}
|
||||
|
|
@ -506,7 +503,7 @@
|
|||
}
|
||||
|
||||
function checkBackingTrackTransition(currentSession) {
|
||||
// handle backing tracks
|
||||
// handle backing tracks
|
||||
if (backing_track_path == null && (currentSession && currentSession.backing_track_path != null)) {
|
||||
playbackControls.startMonitor();
|
||||
}
|
||||
|
|
@ -517,7 +514,7 @@
|
|||
}
|
||||
|
||||
function checkRecordingTransition(currentSession) {
|
||||
// handle claimed recordings
|
||||
// handle claimed recordings
|
||||
if (claimedRecording == null && (currentSession && currentSession.claimed_recording != null)) {
|
||||
// this is a 'started with a claimed_recording' transition.
|
||||
// we need to start a timer to watch for the state of the play session
|
||||
|
|
@ -601,10 +598,11 @@
|
|||
}
|
||||
|
||||
function resetOtherAudioContent() {
|
||||
if ($('.session-recordings .track').length === 0 && $('.session-recordings .download-jamtrack').length === 0) {
|
||||
if ($('.session-recordings .track').length === 0 && $('.session-recordings .download-jamtrack').length === 0 && $('.session-recordings .pending-metronome').length === 0) {
|
||||
$('.session-recordings .when-empty').show();
|
||||
$('.session-recording-name-wrapper').hide();
|
||||
$('.session-recordings .recording-controls').hide();
|
||||
$closePlaybackRecording.show();
|
||||
$('.session-recordings .session-recording-name').text('(No audio loaded)')
|
||||
}
|
||||
}
|
||||
|
|
@ -635,6 +633,7 @@
|
|||
if ($('.session-livetracks .track').length === 0) {
|
||||
$('.session-livetracks .when-empty').show();
|
||||
}
|
||||
checkPendingMetronome();
|
||||
resetOtherAudioContent();
|
||||
|
||||
/**
|
||||
|
|
@ -1209,12 +1208,12 @@
|
|||
});
|
||||
|
||||
var oneOfTheTracks = correspondingTracks[0];
|
||||
var instrumentIcon = context.JK.getInstrumentIcon45(oneOfTheTracks.instrument_id);
|
||||
var instrumentIcon = context.JK.getInstrumentIcon45(oneOfTheTracks.instrument.id);
|
||||
var photoUrl = "/assets/content/icon_recording.png";
|
||||
|
||||
var name = oneOfTheTracks.part
|
||||
if (!name) {
|
||||
name = oneOfTheTracks.instrument;
|
||||
name = '';
|
||||
}
|
||||
|
||||
if(isOpener) {
|
||||
|
|
@ -1345,6 +1344,7 @@
|
|||
setFormFromMetronome()
|
||||
metroCricket = context.jamClient.getMetronomeCricketTestState();
|
||||
setMetronomePlaybackMode()
|
||||
$closePlaybackRecording.show();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -2447,6 +2447,30 @@
|
|||
.fail(app.ajaxError);
|
||||
}
|
||||
|
||||
function checkPendingMetronome() {
|
||||
logger.debug("checkPendingMetronome", sessionModel.isMetronomeOpen(), getMetronomeMasterMixers().length)
|
||||
if(sessionModel.isMetronomeOpen() && getMetronomeMasterMixers().length == 0) {
|
||||
var pendingMetronome = $($templatePendingMetronome.html())
|
||||
|
||||
// hide the open options
|
||||
otherAudioFilled();
|
||||
// fill out the 'media' name
|
||||
$('.session-recordings .session-recording-name').text('Metronome')
|
||||
// and hide the close button
|
||||
$closePlaybackRecording.hide();
|
||||
|
||||
// avoid double addition of pending metronome
|
||||
if($otherAudioContainer.find('.pending-metronome').length === 0) {
|
||||
$otherAudioContainer.append(pendingMetronome)
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
$('.session-recordings .pending-metronome').remove()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function openBackingTrack(e) {
|
||||
|
||||
if($openBackingTrack.is('.disabled')) {
|
||||
|
|
@ -2946,6 +2970,7 @@
|
|||
$openBackingTrack = $('#open-a-backingtrack');
|
||||
$metronomePlaybackSelect = $('#metronome-playback-select')
|
||||
$metronomePlaybackHelp = $('#metronome-playback-help')
|
||||
$templatePendingMetronome = $('#template-pending-metronome');
|
||||
|
||||
events();
|
||||
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@
|
|||
var sessionPageEnterTimeout = null;
|
||||
var startTime = null;
|
||||
var joinDeferred = null;
|
||||
var previousBackingTracks = [];
|
||||
var previousAllTracks = {userTracks: [], backingTracks: [], metronomeTracks: []};
|
||||
var openBackingTrack = null;
|
||||
var shownAudioMediaMixerHelp = false;
|
||||
var controlsLockedForJamTrackRecording = false;
|
||||
|
|
@ -68,6 +68,19 @@
|
|||
}
|
||||
}
|
||||
|
||||
// if any participant has the metronome open, then we say this session has the metronome open
|
||||
function isMetronomeOpen() {
|
||||
var metronomeOpen = false;
|
||||
context._.each(participants(), function(participant) {
|
||||
if(participant.metronome_open) {
|
||||
metronomeOpen = true;
|
||||
return false;
|
||||
}
|
||||
})
|
||||
|
||||
return metronomeOpen;
|
||||
}
|
||||
|
||||
function isPlayingRecording() {
|
||||
// this is the server's state; there is no guarantee that the local tracks
|
||||
// requested from the backend will have corresponding track information
|
||||
|
|
@ -358,7 +371,7 @@
|
|||
}
|
||||
currentSessionId = null;
|
||||
currentParticipants = {}
|
||||
previousBackingTracks = []
|
||||
previousAllTracks = {userTracks: [], backingTracks: [], metronomeTracks: []}
|
||||
openBackingTrack = null
|
||||
shownAudioMediaMixerHelp = false
|
||||
controlsLockedForJamTrackRecording = false;
|
||||
|
|
@ -603,26 +616,27 @@
|
|||
return mixerMode;
|
||||
}
|
||||
|
||||
function syncTracks(backingTracks) {
|
||||
function syncTracks(allTracks) {
|
||||
// double check that we are in session, since a bunch could have happened since then
|
||||
if(!inSession()) {
|
||||
logger.debug("dropping queued up sync tracks because no longer in session");
|
||||
return null;
|
||||
}
|
||||
|
||||
// this is a local change to our tracks. we need to tell the server about our updated track information
|
||||
var inputTracks = context.JK.TrackHelpers.getUserTracks(context.jamClient);
|
||||
|
||||
// backingTracks can be passed in as an optimization, so that we don't hit the backend excessively
|
||||
if(backingTracks === undefined ) {
|
||||
backingTracks = context.JK.TrackHelpers.getBackingTracks(context.jamClient);
|
||||
if(allTracks === undefined) {
|
||||
allTracks = context.JK.TrackHelpers.getTrackInfo(context.jamClient);
|
||||
}
|
||||
|
||||
var inputTracks = allTracks.userTracks;
|
||||
var backingTracks = allTracks.backingTracks;
|
||||
var metronomeTracks = allTracks.metronomeTracks;
|
||||
|
||||
// create a trackSync request based on backend data
|
||||
var syncTrackRequest = {};
|
||||
syncTrackRequest.client_id = app.clientId;
|
||||
syncTrackRequest.tracks = inputTracks;
|
||||
syncTrackRequest.backing_tracks = backingTracks;
|
||||
syncTrackRequest.metronome_open = metronomeTracks.length > 0;
|
||||
syncTrackRequest.id = id();
|
||||
|
||||
return rest.putTrackSyncChange(syncTrackRequest)
|
||||
|
|
@ -793,17 +807,27 @@
|
|||
}
|
||||
else if(inSession() && (text == 'RebuildMediaControl' || text == 'RebuildRemoteUserControl')) {
|
||||
|
||||
var backingTracks = context.JK.TrackHelpers.getBackingTracks(context.jamClient);
|
||||
var allTracks = context.JK.TrackHelpers.getTrackInfo(context.jamClient);
|
||||
var backingTracks = allTracks.backingTracks;
|
||||
var previousBackingTracks = previousAllTracks.backingTracks;
|
||||
var metronomeTracks = allTracks.metronomeTracks;
|
||||
var previousMetronomeTracks = previousAllTracks.metronomeTracks;
|
||||
|
||||
// the way we know if backing tracks changes, or recordings are opened, is via this event.
|
||||
// but we want to report to the user when backing tracks change; so we need to detect change on our own
|
||||
if(!(previousBackingTracks.length == 0 && backingTracks.length == 0) && previousBackingTracks != backingTracks) {
|
||||
logger.debug("backing tracks changed", previousBackingTracks, backingTracks)
|
||||
syncTracks(backingTracks);
|
||||
syncTracks(allTracks);
|
||||
}
|
||||
else if(!(previousMetronomeTracks.length == 0 && metronomeTracks.length == 0) && previousMetronomeTracks != metronomeTracks) {
|
||||
logger.debug("metronome state changed ", previousMetronomeTracks, metronomeTracks)
|
||||
syncTracks(allTracks);
|
||||
}
|
||||
else {
|
||||
refreshCurrentSession(true);
|
||||
}
|
||||
|
||||
previousAllTracks = allTracks;
|
||||
}
|
||||
else if(inSession() && (text == 'Global Peer Input Mixer Mode')) {
|
||||
setMixerMode(MIX_MODES.MASTER);
|
||||
|
|
@ -840,6 +864,7 @@
|
|||
this.isPersonalMixMode = isPersonalMixMode;
|
||||
this.getMixMode = getMixMode;
|
||||
this.selfOpenedJamTracks = selfOpenedJamTracks;
|
||||
this.isMetronomeOpen = isMetronomeOpen;
|
||||
this.areControlsLockedForJamTrackRecording = areControlsLockedForJamTrackRecording;
|
||||
this.lockControlsforJamTrackRecording = lockControlsforJamTrackRecording;
|
||||
this.unlockControlsforJamTrackRecording = unlockControlsforJamTrackRecording;
|
||||
|
|
|
|||
|
|
@ -14,9 +14,28 @@
|
|||
// take all necessary arguments to complete its work.
|
||||
context.JK.TrackHelpers = {
|
||||
|
||||
getTracks: function(jamClient, groupId) {
|
||||
getTrackInfo: function(jamClient) {
|
||||
|
||||
var allTracks = context.jamClient.SessionGetAllControlState(true);
|
||||
|
||||
var userTracks = context.JK.TrackHelpers.getUserTracks(jamClient, allTracks);
|
||||
var backingTracks = context.JK.TrackHelpers.getBackingTracks(jamClient, allTracks);
|
||||
var metronomeTracks = context.JK.TrackHelpers.getTracks(jamClient, 12);
|
||||
|
||||
return {
|
||||
userTracks: userTracks,
|
||||
backingTracks: backingTracks,
|
||||
metronomeTracks: metronomeTracks
|
||||
}
|
||||
},
|
||||
|
||||
// allTracks is the result of SessionGetAllControlState; as an optimization
|
||||
getTracks: function(jamClient, groupId, allTracks) {
|
||||
var tracks = [];
|
||||
var allTracks = context.jamClient.SessionGetAllControlState(true);
|
||||
|
||||
if(!allTracks) {
|
||||
allTracks = context.jamClient.SessionGetAllControlState(true);
|
||||
}
|
||||
//var trackIds = jamClient.SessionGetIDs();
|
||||
//var allTracks = jamClient.SessionGetControlState(trackIds, true);
|
||||
|
||||
|
|
@ -30,8 +49,9 @@
|
|||
return tracks;
|
||||
},
|
||||
|
||||
getBackingTracks: function(jamClient) {
|
||||
var mediaTracks = context.JK.TrackHelpers.getTracks(jamClient, 4);
|
||||
// allTracks is the result of SessionGetAllControlState; as an optimization
|
||||
getBackingTracks: function(jamClient, allTracks) {
|
||||
var mediaTracks = context.JK.TrackHelpers.getTracks(jamClient, 4, allTracks);
|
||||
|
||||
var backingTracks = []
|
||||
context._.each(mediaTracks, function(mediaTrack) {
|
||||
|
|
@ -56,11 +76,11 @@
|
|||
* from jamClient. If none exist there, the first instrument from the
|
||||
* user's profile is used.
|
||||
*/
|
||||
getUserTracks: function(jamClient) {
|
||||
getUserTracks: function(jamClient, allTracks) {
|
||||
var localMusicTracks = [];
|
||||
var i;
|
||||
|
||||
localMusicTracks = context.JK.TrackHelpers.getTracks(jamClient, 2);
|
||||
localMusicTracks = context.JK.TrackHelpers.getTracks(jamClient, 2, allTracks);
|
||||
|
||||
var trackObjects = [];
|
||||
|
||||
|
|
|
|||
|
|
@ -62,6 +62,18 @@
|
|||
});
|
||||
}
|
||||
|
||||
function launchGenreSelectorDialog(type, genres, callback) {
|
||||
var genreSelectorDialog = new JK.GenreSelectorDialog(JK.app, type, genres, callback);
|
||||
genreSelectorDialog.initialize();
|
||||
return genreSelectorDialog.showDialog();
|
||||
}
|
||||
|
||||
function launchRecordingSelectorDialog(recordings, selectedRecordings, callback) {
|
||||
var recordingSelectorDialog = new JK.RecordingSelectorDialog(JK.app, recordings, selectedRecordings, callback);
|
||||
recordingSelectorDialog.initialize();
|
||||
return recordingSelectorDialog.showDialog();
|
||||
}
|
||||
|
||||
this.addSessionLike = addSessionLike;
|
||||
this.addRecordingLike = addRecordingLike;
|
||||
this.launchCommentDialog = launchCommentDialog;
|
||||
|
|
@ -70,6 +82,8 @@
|
|||
this.launchRsvpCancelDialog = launchRsvpCancelDialog;
|
||||
this.launchRsvpCreateSlotDialog = launchRsvpCreateSlotDialog;
|
||||
this.launchSessionStartDialog = launchSessionStartDialog;
|
||||
this.launchGenreSelectorDialog = launchGenreSelectorDialog;
|
||||
this.launchRecordingSelectorDialog = launchRecordingSelectorDialog;
|
||||
|
||||
return this;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
context.JK = context.JK || {};
|
||||
var logger = context.JK.logger;
|
||||
var api = context.JK.Rest();
|
||||
var AUDIO_DEVICE_BEHAVIOR = context.JK.AUDIO_DEVICE_BEHAVIOR;
|
||||
|
||||
var ALERT_NAMES = context.JK.ALERT_NAMES;
|
||||
|
|
@ -22,6 +23,10 @@
|
|||
|
||||
var os = null;
|
||||
|
||||
context.JK.getGenreList = function() {
|
||||
return api.getGenres();
|
||||
}
|
||||
|
||||
context.JK.stringToBool = function (s) {
|
||||
switch (s.toLowerCase()) {
|
||||
case "true":
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@
|
|||
}
|
||||
|
||||
form {
|
||||
padding-right:10%;
|
||||
//padding-right:10%;
|
||||
}
|
||||
|
||||
label {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
@import "client/common.css.scss";
|
||||
@import "common.css.scss";
|
||||
|
||||
|
||||
#account-profile-experience {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
@import "common.css.scss";
|
||||
|
||||
#account-profile-interests {
|
||||
.interest {
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
a.help {
|
||||
font-weight: normal;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
div.genres {
|
||||
width: 20%;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
a.select-genre {
|
||||
text-decoration: underline;
|
||||
font-size: 12px;
|
||||
font-weight: normal !important;
|
||||
}
|
||||
|
||||
span.genre-list {
|
||||
font-style: italic;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.interest-options {
|
||||
width: 30%;
|
||||
margin-bottom: 15px;
|
||||
|
||||
label {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
input[type=text].rate {
|
||||
width: 100px;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
@import "common.css.scss";
|
||||
|
||||
#account-profile-samples {
|
||||
|
||||
.sample {
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.presence {
|
||||
margin: 3px 30px 15px 0px;
|
||||
|
||||
input {
|
||||
width:200px;
|
||||
}
|
||||
}
|
||||
|
||||
.samples {
|
||||
width: 30%;
|
||||
|
||||
input {
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
.sample {
|
||||
margin: 3px 5px 10px 0px;
|
||||
}
|
||||
|
||||
.sample-list {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -593,16 +593,4 @@ body.jam .icheckbox_minimal {
|
|||
display:inline-block;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#jamblaster-notice {
|
||||
position:absolute;
|
||||
width:100%;
|
||||
bottom:105%;
|
||||
border-color:#ED3618;
|
||||
border-style:solid;
|
||||
border-width:1px;
|
||||
padding:10px;
|
||||
text-align:center;
|
||||
@include border_box_sizing;
|
||||
}
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
.metronome-playback-mode-selector-popup {
|
||||
.bt-content {
|
||||
width:160px;
|
||||
width:180px;
|
||||
background-color:#333;
|
||||
overflow:auto;
|
||||
border:1px solid #ED3618;
|
||||
|
|
|
|||
|
|
@ -9,6 +9,25 @@
|
|||
padding:0;
|
||||
}
|
||||
}
|
||||
|
||||
div.logo {
|
||||
text-align: bottom;
|
||||
}
|
||||
|
||||
img.logo {
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
ul {
|
||||
margin:0px 0px 10px 0px;
|
||||
padding:0px;
|
||||
}
|
||||
|
||||
li {
|
||||
margin-left: 15px;
|
||||
margin-bottom: 0px !important;
|
||||
list-style: disc;
|
||||
}
|
||||
}
|
||||
|
||||
.profile-head {
|
||||
|
|
|
|||
|
|
@ -15,6 +15,16 @@
|
|||
position:relative;
|
||||
}
|
||||
|
||||
.pending-metronome {
|
||||
.spinner-large {
|
||||
margin:20px auto 0;
|
||||
text-align:center;
|
||||
}
|
||||
p {
|
||||
text-align:center;
|
||||
font-size:14px;
|
||||
}
|
||||
}
|
||||
|
||||
.track {
|
||||
width:70px;
|
||||
|
|
|
|||
|
|
@ -342,6 +342,11 @@
|
|||
margin-top: 20px;
|
||||
}
|
||||
|
||||
a.forever-network-test {
|
||||
margin-top:20px;
|
||||
display:none;
|
||||
}
|
||||
|
||||
.network-test-score {
|
||||
height: 24px;
|
||||
padding: 10px;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
@import "client/common";
|
||||
|
||||
#genre-selector-dialog {
|
||||
|
||||
min-height:initial;
|
||||
|
||||
.dialog-inner {
|
||||
color:white;
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
margin-bottom:10px;
|
||||
}
|
||||
}
|
||||
|
|
@ -31,6 +31,7 @@
|
|||
left: 15%;
|
||||
font-size: 12px;
|
||||
padding-top:5px;
|
||||
z-index:-1;
|
||||
|
||||
a {
|
||||
margin:0 10px;
|
||||
|
|
@ -40,5 +41,11 @@
|
|||
.paginator-holder {
|
||||
padding-top:3px;
|
||||
}
|
||||
|
||||
.recording-wrapper {
|
||||
height:290px;
|
||||
overflow:auto;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
@import "client/common";
|
||||
|
||||
#recording-selector-dialog {
|
||||
|
||||
min-height:initial;
|
||||
|
||||
.dialog-inner {
|
||||
color:white;
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
margin-bottom:10px;
|
||||
}
|
||||
}
|
||||
|
|
@ -23,15 +23,6 @@ class ApiJamTracksController < ApiController
|
|||
render "api_jam_tracks/purchased", :layout => nil
|
||||
end
|
||||
|
||||
def downloads
|
||||
sample_rate = params[:sample_rate].nil? ? nil : params[:sample_rate].to_i
|
||||
begin
|
||||
render :json => JamTrack.list_downloads(current_user, params[:limit], params[:since], sample_rate), :status => 200
|
||||
rescue
|
||||
render :json => { :message => "could not produce list of files" }, :status => 403
|
||||
end
|
||||
end
|
||||
|
||||
def download
|
||||
if @jam_track_right.valid?
|
||||
sample_rate = params[:sample_rate].nil? ? nil : params[:sample_rate].to_i
|
||||
|
|
|
|||
|
|
@ -165,7 +165,7 @@ class ApiMusicSessionsController < ApiController
|
|||
|
||||
def show
|
||||
unless @music_session.can_see? current_user
|
||||
raise ActiveRecord::RecordNotFound
|
||||
raise JamRuby::PermissionError
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -357,7 +357,7 @@ class ApiMusicSessionsController < ApiController
|
|||
end
|
||||
|
||||
def track_sync
|
||||
@tracks = MusicSessionManager.new.sync_tracks(@music_session, params[:client_id], params[:tracks], params[:backing_tracks])
|
||||
@tracks = MusicSessionManager.new.sync_tracks(@music_session, params[:client_id], params[:tracks], params[:backing_tracks], params[:metronome_open])
|
||||
|
||||
unless @tracks.kind_of? Array
|
||||
# we have to do this because api_session_detail_url will fail with a bad @tracks
|
||||
|
|
|
|||
|
|
@ -56,7 +56,6 @@ class ApiRecurlyController < ApiController
|
|||
|
||||
def place_order
|
||||
error=nil
|
||||
puts "PLACING ORDER #{params.inspect}"
|
||||
response = {jam_tracks:[]}
|
||||
|
||||
# 1st confirm that all specified JamTracks exist
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ else
|
|||
|
||||
child(:connections => :participants) {
|
||||
collection @music_sessions, :object_root => false
|
||||
attributes :ip_address, :client_id, :joined_session_at, :audio_latency, :id
|
||||
attributes :ip_address, :client_id, :joined_session_at, :audio_latency, :id, :metronome_open
|
||||
|
||||
node :user do |connection|
|
||||
{ :id => connection.user.id, :photo_url => connection.user.photo_url, :name => connection.user.name, :is_friend => connection.user.friends?(current_user), :connection_state => connection.aasm_state }
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
object @profile
|
||||
|
||||
attributes :id, :first_name, :last_name, :name, :city, :state, :country, :location, :online, :photo_url, :musician, :gender, :birth_date, :internet_service_provider, :friend_count, :liker_count, :like_count, :follower_count, :following_count, :recording_count, :session_count, :biography, :favorite_count, :audio_latency, :upcoming_session_count, :age, :website, :skill_level, :concert_count, :studio_session_count, :virtual_band, :virtual_band_commitment, :traditional_band, :traditional_band_commitment, :traditional_band_touring, :paid_sessions, :paid_sessions_hourly_rate,
|
||||
:paid_sessions_daily_rate, :free_sessions, :cowriting, :cowriting_purpose
|
||||
:paid_sessions_daily_rate, :free_sessions, :cowriting, :cowriting_purpose, :subscribe_email
|
||||
|
||||
child :online_presences => :online_presences do
|
||||
attributes :id, :service_type, :username
|
||||
|
|
@ -11,7 +11,7 @@ child :performance_samples => :performance_samples do
|
|||
attributes :id, :url, :service_type, :claimed_recording_id, :service_id, :description
|
||||
|
||||
child :claimed_recording => :claimed_recording do
|
||||
attributes :name
|
||||
attributes :id, :name
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -30,8 +30,4 @@ end
|
|||
|
||||
child :musician_instruments => :instruments do
|
||||
attributes :description, :proficiency_level, :priority, :instrument_id
|
||||
end
|
||||
|
||||
# child :genres do
|
||||
# attributes :description, :id
|
||||
# end
|
||||
end
|
||||