merging feature/musician_profile_enhancements
This commit is contained in:
commit
c3ede10f1d
|
|
@ -24,7 +24,7 @@ ActiveAdmin.register JamRuby::JamTrack, :as => 'JamTracks' do
|
|||
|
||||
column :original_artist
|
||||
column :name
|
||||
column :flags do |jam_track| jam_track.duplicate_positions? ? 'DUP POSITIONS' : '' end
|
||||
column :onboarding_flags do |jam_track| jam_track.onboard_warnings end
|
||||
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
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
= f.input :publisher, :input_html => { :rows=>1, :maxlength=>1000 }
|
||||
= f.input :licensor, collection: JamRuby::JamTrackLicensor.all, include_blank: true
|
||||
= f.input :genre, collection: JamRuby::Genre.all, include_blank: false
|
||||
= f.input :duration, hint: 'this should rarely need editing because it comes from the import process'
|
||||
= f.input :sales_region, collection: JamRuby::JamTrack::SALES_REGION, include_blank: false
|
||||
= f.input :price, :required => true, :input_html => {type: 'numeric'}
|
||||
= f.input :pro_ascap, :label => 'ASCAP royalties due?'
|
||||
|
|
|
|||
|
|
@ -5,11 +5,14 @@
|
|||
= 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
|
||||
- if !f.object.nil? && f.object.track_type != 'Master'
|
||||
= 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
|
||||
a href=f.object.preview_public_url('ogg') style='padding:0 0 0 20px'
|
||||
| Download Preview (ogg)
|
||||
a href=f.object.preview_public_url('mp3') style='padding:0 0 0 20px'
|
||||
| Download Preview (mp3)
|
||||
|
||||
// temporarily disable
|
||||
- if f.object.new_record?
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ class JamRuby::JamTrackTrack
|
|||
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?
|
||||
|
|
@ -60,6 +59,7 @@ class JamRuby::JamTrackTrack
|
|||
|
||||
input = File.join(tmp_dir, 'in.ogg')
|
||||
output = File.join(tmp_dir, 'out.ogg')
|
||||
output_mp3 = File.join(tmp_dir, 'out.mp3')
|
||||
|
||||
start = self.preview_start_time.to_f / 1000
|
||||
stop = start + 20
|
||||
|
|
@ -80,16 +80,52 @@ class JamRuby::JamTrackTrack
|
|||
@@log.debug("fail #{result_code}")
|
||||
@preview_generate_error = "unable to execute cut command #{sox_output}"
|
||||
else
|
||||
@@log.debug("uploading preview to #{self.preview_filename}")
|
||||
# now create mp3 off of ogg preview
|
||||
|
||||
s3_manager.upload(self.preview_filename, output)
|
||||
convert_mp3_cmd = "#{APP_CONFIG.ffmpeg_path} -i \"#{output}\" -ab 192k \"#{output_mp3}\""
|
||||
|
||||
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!
|
||||
@@log.debug("converting to mp3 using: " + convert_mp3_cmd)
|
||||
|
||||
convert_output = `#{convert_mp3_cmd}`
|
||||
|
||||
result_code = $?.to_i
|
||||
|
||||
if result_code != 0
|
||||
@@log.debug("fail #{result_code}")
|
||||
@preview_generate_error = "unable to execute mp3 convert command #{convert_output}"
|
||||
else
|
||||
ogg_digest = ::Digest::MD5.file(output)
|
||||
mp3_digest = ::Digest::MD5.file(output_mp3)
|
||||
self["preview_md5"] = ogg_md5 = ogg_digest.hexdigest
|
||||
self["preview_mp3_md5"] = mp3_md5 = mp3_digest.hexdigest
|
||||
|
||||
@@log.debug("uploading ogg preview to #{self.preview_filename('ogg')}")
|
||||
s3_public_manager.upload(self.preview_filename(ogg_md5, 'ogg'), output, content_type: 'audio/ogg', content_md5: ogg_digest.base64digest)
|
||||
@@log.debug("uploading mp3 preview to #{self.preview_filename('mp3')}")
|
||||
s3_public_manager.upload(self.preview_filename(mp3_md5, 'mp3'), output_mp3, content_type: 'audio/mpeg', content_md5: mp3_digest.base64)
|
||||
|
||||
self.skip_uploader = true
|
||||
|
||||
original_ogg_preview_url = self["preview_url"]
|
||||
original_mp3_preview_url = self["preview_mp3_url"]
|
||||
|
||||
# and finally update the JamTrackTrack with the new info
|
||||
self["preview_url"] = self.preview_filename(ogg_md5, 'ogg')
|
||||
self["preview_length"] = File.new(output).size
|
||||
# and finally update the JamTrackTrack with the new info
|
||||
self["preview_mp3_url"] = self.preview_filename(mp3_md5, 'mp3')
|
||||
self["preview_mp3_length"] = File.new(output_mp3).size
|
||||
self.save!
|
||||
|
||||
# if all that worked, now delete old previews, if present
|
||||
begin
|
||||
s3_public_manager.delete(original_ogg_preview_url) if original_ogg_preview_url && original_ogg_preview_url != self["preview_url"]
|
||||
s3_public_manager.delete(original_mp3_preview_url) if original_mp3_preview_url && original_mp3_preview_url != track["preview_mp3_url"]
|
||||
rescue
|
||||
puts "UNABLE TO CLEANUP OLD PREVIEW URL"
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
rescue Exception => e
|
||||
|
|
|
|||
|
|
@ -276,4 +276,6 @@ user_reuse_card_and_reedem.sql
|
|||
jam_track_id_to_varchar.sql
|
||||
drop_position_unique_jam_track.sql
|
||||
recording_client_metadata.sql
|
||||
preview_support_mp3.sql
|
||||
jam_track_duration.sql
|
||||
musician_search.sql
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
ALTER TABLE jam_tracks ADD COLUMN duration INTEGER;
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
ALTER TABLE jam_track_tracks ADD COLUMN preview_mp3_url VARCHAR;
|
||||
ALTER TABLE jam_track_tracks ADD COLUMN preview_mp3_md5 VARCHAR;
|
||||
ALTER TABLE jam_track_tracks ADD COLUMN preview_mp3_length BIGINT;
|
||||
UPDATE jam_track_tracks SET preview_url = NULL where track_type = 'Master';
|
||||
|
|
@ -30,6 +30,7 @@ require "jam_ruby/errors/jam_argument_error"
|
|||
require "jam_ruby/errors/conflict_error"
|
||||
require "jam_ruby/lib/app_config"
|
||||
require "jam_ruby/lib/s3_manager_mixin"
|
||||
require "jam_ruby/lib/s3_public_manager_mixin"
|
||||
require "jam_ruby/lib/module_overrides"
|
||||
require "jam_ruby/lib/s3_util"
|
||||
require "jam_ruby/lib/s3_manager"
|
||||
|
|
|
|||
|
|
@ -19,6 +19,10 @@ module JamRuby
|
|||
@s3_manager ||= S3Manager.new(APP_CONFIG.aws_bucket, APP_CONFIG.aws_access_key_id, APP_CONFIG.aws_secret_access_key)
|
||||
end
|
||||
|
||||
def public_jamkazam_s3_manager
|
||||
@public_s3_manager ||= S3Manager.new(APP_CONFIG.aws_bucket_public, APP_CONFIG.aws_access_key_id, APP_CONFIG.aws_secret_access_key)
|
||||
end
|
||||
|
||||
def finish(reason, detail)
|
||||
self.reason = reason
|
||||
self.detail = detail
|
||||
|
|
@ -93,6 +97,7 @@ module JamRuby
|
|||
self.name = metadata["name"] || name
|
||||
|
||||
if jam_track.new_record?
|
||||
jam_track.id = "#{JamTrack.count + 1}" # default is UUID, but the initial import was based on auto-increment ID, so we'll maintain that
|
||||
jam_track.status = 'Staging'
|
||||
jam_track.metalocation = metalocation
|
||||
jam_track.original_artist = metadata["original_artist"] || original_artist
|
||||
|
|
@ -228,7 +233,7 @@ module JamRuby
|
|||
part = potential_instrument_original if !part
|
||||
|
||||
{instrument: instrument,
|
||||
part: part}
|
||||
part: part}
|
||||
|
||||
end
|
||||
|
||||
|
|
@ -259,7 +264,7 @@ module JamRuby
|
|||
|
||||
if stem_location
|
||||
bits = filename_no_ext[stem_location..-1].split('-')
|
||||
bits.collect! {|bit| bit.strip}
|
||||
bits.collect! { |bit| bit.strip }
|
||||
|
||||
possible_instrument = nil
|
||||
possible_part = nil
|
||||
|
|
@ -424,6 +429,15 @@ module JamRuby
|
|||
track["url_48"] = ogg_48000_s3_path
|
||||
track["md5_48"] = 'md5'
|
||||
track["length_48"] = 1
|
||||
|
||||
# we can't fake the preview as easily because we don't know the MD5 of the current item
|
||||
#track["preview_md5"] = 'md5'
|
||||
#track["preview_mp3_md5"] = 'md5'
|
||||
#track["preview_url"] = track.preview_filename('md5', 'ogg')
|
||||
#track["preview_length"] = 1
|
||||
#track["preview_mp3_url"] = track.preview_filename('md5', 'mp3')
|
||||
#track["preview_mp3_length"] = 1
|
||||
#track["preview_start_time"] = 0
|
||||
else
|
||||
wav_file = File.join(tmp_dir, basename)
|
||||
|
||||
|
|
@ -456,15 +470,26 @@ module JamRuby
|
|||
|
||||
jamkazam_s3_manager.upload(ogg_48000_s3_path, ogg_48000)
|
||||
|
||||
ogg_44100_digest = ::Digest::MD5.file(ogg_44100)
|
||||
# and finally update the JamTrackTrack with the new info
|
||||
track["url_44"] = ogg_44100_s3_path
|
||||
track["md5_44"] = ::Digest::MD5.file(ogg_44100).hexdigest
|
||||
track["md5_44"] = ogg_44100_digest.hexdigest
|
||||
track["length_44"] = File.new(ogg_44100).size
|
||||
|
||||
track["url_48"] = ogg_48000_s3_path
|
||||
track["md5_48"] = ::Digest::MD5.file(ogg_48000).hexdigest
|
||||
track["length_48"] = File.new(ogg_48000).size
|
||||
|
||||
synchronize_duration(jam_track, ogg_44100)
|
||||
|
||||
# convert entire master ogg file to mp3, and push both to public destination
|
||||
preview_succeeded = synchronize_master_preview(track, tmp_dir, ogg_44100, ogg_44100_digest) if track.track_type == 'Master'
|
||||
|
||||
if !preview_succeeded
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
track.save!
|
||||
|
|
@ -478,6 +503,77 @@ module JamRuby
|
|||
return true
|
||||
end
|
||||
|
||||
def synchronize_duration(jam_track, ogg_44100)
|
||||
duration_command = "soxi -D \"#{ogg_44100}\""
|
||||
output = `#{duration_command}`
|
||||
|
||||
result_code = $?.to_i
|
||||
|
||||
if result_code == 0
|
||||
duration = output.to_f.round
|
||||
jam_track.duration = duration
|
||||
else
|
||||
@@log.warn("unable to determine duration for jam_track #{jam_track.name}. output #{output}")
|
||||
end
|
||||
true
|
||||
end
|
||||
|
||||
def synchronize_master_preview(track, tmp_dir, ogg_44100, ogg_digest)
|
||||
|
||||
begin
|
||||
mp3_44100 = File.join(tmp_dir, 'output-preview-44100.mp3')
|
||||
convert_mp3_cmd = "#{APP_CONFIG.ffmpeg_path} -i \"#{ogg_44100}\" -ab 192k \"#{mp3_44100}\""
|
||||
@@log.debug("converting to mp3 using: " + convert_mp3_cmd)
|
||||
|
||||
convert_output = `#{convert_mp3_cmd}`
|
||||
|
||||
mp3_digest = ::Digest::MD5.file(mp3_44100)
|
||||
|
||||
track["preview_md5"] = ogg_md5 = ogg_digest.hexdigest
|
||||
track["preview_mp3_md5"] = mp3_md5 = mp3_digest.hexdigest
|
||||
|
||||
# upload 44100 ogg and mp3 to public location as well
|
||||
@@log.debug("uploading ogg preview to #{track.preview_filename('ogg')}")
|
||||
public_jamkazam_s3_manager.upload(track.preview_filename(ogg_digest.hexdigest, 'ogg'), ogg_44100, content_type: 'audio/ogg', content_md5: ogg_digest.base64digest)
|
||||
@@log.debug("uploading mp3 preview to #{track.preview_filename('mp3')}")
|
||||
public_jamkazam_s3_manager.upload(track.preview_filename(mp3_digest.hexdigest, 'mp3'), mp3_44100, content_type: 'audio/mpeg', content_md5: mp3_digest.base64digest)
|
||||
|
||||
|
||||
track.skip_uploader = true
|
||||
|
||||
original_ogg_preview_url = track["preview_url"]
|
||||
original_mp3_preview_url = track["preview_mp3_url"]
|
||||
|
||||
# and finally update the JamTrackTrack with the new info
|
||||
track["preview_url"] = track.preview_filename(ogg_md5, 'ogg')
|
||||
track["preview_length"] = File.new(ogg_44100).size
|
||||
# and finally update the JamTrackTrack with the new info
|
||||
track["preview_mp3_url"] = track.preview_filename(mp3_md5, 'mp3')
|
||||
track["preview_mp3_length"] = File.new(mp3_44100).size
|
||||
track["preview_start_time"] = 0
|
||||
|
||||
if !track.save
|
||||
finish("save_master_preview", track.errors.to_s)
|
||||
return false
|
||||
end
|
||||
|
||||
# if all that worked, now delete old previews, if present
|
||||
begin
|
||||
public_jamkazam_s3_manager.delete(original_ogg_preview_url) if original_ogg_preview_url && original_ogg_preview_url != track["preview_url"]
|
||||
public_jamkazam_s3_manager.delete(original_mp3_preview_url) if original_mp3_preview_url && original_mp3_preview_url != track["preview_mp3_url"]
|
||||
rescue
|
||||
puts "UNABLE TO CLEANUP OLD PREVIEW URL"
|
||||
end
|
||||
rescue Exception => e
|
||||
finish("sync_master_preview_exception", e.to_s)
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
def fetch_all_files(s3_path)
|
||||
JamTrackImporter::s3_manager.list_files(s3_path)
|
||||
end
|
||||
|
|
@ -533,6 +629,10 @@ module JamRuby
|
|||
@s3_manager ||= S3Manager.new(APP_CONFIG.aws_bucket_jamtracks, APP_CONFIG.aws_access_key_id, APP_CONFIG.aws_secret_access_key)
|
||||
end
|
||||
|
||||
def private_s3_manager
|
||||
@s3_manager ||= S3Manager.new(APP_CONFIG.aws_bucket, APP_CONFIG.aws_access_key_id, APP_CONFIG.aws_secret_access_key)
|
||||
end
|
||||
|
||||
|
||||
def dry_run
|
||||
s3_manager.list_directories('audio').each do |original_artist|
|
||||
|
|
@ -554,6 +654,139 @@ module JamRuby
|
|||
|
||||
end
|
||||
|
||||
def synchronize_jamtrack_master_preview(jam_track)
|
||||
importer = JamTrackImporter.new
|
||||
importer.name = jam_track.name
|
||||
|
||||
master_track = jam_track.master_track
|
||||
|
||||
if master_track
|
||||
Dir.mktmpdir do |tmp_dir|
|
||||
ogg_44100 = File.join(tmp_dir, 'input.ogg')
|
||||
private_s3_manager.download(master_track.url_by_sample_rate(44), ogg_44100)
|
||||
ogg_44100_digest = ::Digest::MD5.file(ogg_44100)
|
||||
if importer.synchronize_master_preview(master_track, tmp_dir, ogg_44100, ogg_44100_digest)
|
||||
importer.finish("success", nil)
|
||||
end
|
||||
end
|
||||
else
|
||||
importer.finish('no_master_track', nil)
|
||||
end
|
||||
|
||||
importer
|
||||
end
|
||||
|
||||
def synchronize_jamtrack_master_previews
|
||||
importers = []
|
||||
|
||||
JamTrack.all.each do |jam_track|
|
||||
importers << synchronize_jamtrack_master_preview(jam_track)
|
||||
end
|
||||
|
||||
@@log.info("SUMMARY")
|
||||
@@log.info("-------")
|
||||
importers.each do |importer|
|
||||
if importer
|
||||
if importer.reason == "success" || importer.reason == "jam_track_exists"
|
||||
@@log.info("#{importer.name} #{importer.reason}")
|
||||
else
|
||||
@@log.error("#{importer.name} failed to import.")
|
||||
@@log.error("#{importer.name} reason=#{importer.reason}")
|
||||
@@log.error("#{importer.name} detail=#{importer.detail}")
|
||||
end
|
||||
else
|
||||
@@log.error("NULL IMPORTER")
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
def synchronize_duration(jam_track)
|
||||
importer = JamTrackImporter.new
|
||||
importer.name = jam_track.name
|
||||
|
||||
master_track = jam_track.master_track
|
||||
if master_track
|
||||
Dir.mktmpdir do |tmp_dir|
|
||||
ogg_44100 = File.join(tmp_dir, 'input.ogg')
|
||||
private_s3_manager.download(master_track.url_by_sample_rate(44), ogg_44100)
|
||||
|
||||
if importer.synchronize_duration(jam_track, ogg_44100)
|
||||
jam_track.save!
|
||||
importer.finish("success", nil)
|
||||
end
|
||||
end
|
||||
else
|
||||
importer.finish('no_duration', nil)
|
||||
end
|
||||
|
||||
importer
|
||||
end
|
||||
|
||||
def synchronize_durations
|
||||
importers = []
|
||||
|
||||
JamTrack.all.each do |jam_track|
|
||||
importers << synchronize_duration(jam_track)
|
||||
end
|
||||
|
||||
@@log.info("SUMMARY")
|
||||
@@log.info("-------")
|
||||
importers.each do |importer|
|
||||
if importer
|
||||
if importer.reason == "success" || importer.reason == "jam_track_exists"
|
||||
@@log.info("#{importer.name} #{importer.reason}")
|
||||
else
|
||||
@@log.error("#{importer.name} failed to import.")
|
||||
@@log.error("#{importer.name} reason=#{importer.reason}")
|
||||
@@log.error("#{importer.name} detail=#{importer.detail}")
|
||||
end
|
||||
else
|
||||
@@log.error("NULL IMPORTER")
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
def download_master(jam_track)
|
||||
importer = JamTrackImporter.new
|
||||
importer.name = jam_track.name
|
||||
|
||||
Dir.mkdir('tmp') unless Dir.exists?('tmp')
|
||||
Dir.mkdir('tmp/jam_track_masters') unless Dir.exists?('tmp/jam_track_masters')
|
||||
|
||||
master_track = jam_track.master_track
|
||||
if master_track
|
||||
ogg_44100 = File.join('tmp/jam_track_masters', "#{jam_track.original_artist} - #{jam_track.name}.ogg")
|
||||
private_s3_manager.download(master_track.url_by_sample_rate(44), ogg_44100)
|
||||
end
|
||||
importer
|
||||
end
|
||||
|
||||
def download_masters
|
||||
importers = []
|
||||
|
||||
JamTrack.all.each do |jam_track|
|
||||
importers << download_master(jam_track)
|
||||
end
|
||||
|
||||
@@log.info("SUMMARY")
|
||||
@@log.info("-------")
|
||||
importers.each do |importer|
|
||||
if importer
|
||||
if importer.reason == "success"
|
||||
@@log.info("#{importer.name} #{importer.reason}")
|
||||
else
|
||||
@@log.error("#{importer.name} failed to download.")
|
||||
@@log.error("#{importer.name} reason=#{importer.reason}")
|
||||
@@log.error("#{importer.name} detail=#{importer.detail}")
|
||||
end
|
||||
else
|
||||
@@log.error("NULL IMPORTER")
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
def synchronize_all(options)
|
||||
importers = []
|
||||
|
|
@ -607,14 +840,14 @@ module JamRuby
|
|||
|
||||
def load_metalocation(metalocation)
|
||||
begin
|
||||
data = s3_manager.read_all(metalocation)
|
||||
data = s3_manager.read_all(metalocation)
|
||||
return YAML.load(data)
|
||||
rescue AWS::S3::Errors::NoSuchKey
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
def create_from_metalocation(meta, metalocation, options = {skip_audio_upload:false})
|
||||
def create_from_metalocation(meta, metalocation, options = {skip_audio_upload: false})
|
||||
jam_track = JamTrack.new
|
||||
sync_from_metadata(jam_track, meta, metalocation, options)
|
||||
end
|
||||
|
|
@ -628,7 +861,7 @@ module JamRuby
|
|||
|
||||
JamTrack.transaction do
|
||||
#begin
|
||||
jam_track_importer.synchronize(jam_track, meta, metalocation, options)
|
||||
jam_track_importer.synchronize(jam_track, meta, metalocation, options)
|
||||
#rescue Exception => e
|
||||
# jam_track_importer.finish("unhandled_exception", e.to_s)
|
||||
#end
|
||||
|
|
|
|||
|
|
@ -44,6 +44,10 @@ module JamRuby
|
|||
s3_bucket.objects[key].url_for(operation, options).to_s
|
||||
end
|
||||
|
||||
def public_url(key, options = @@def_opts)
|
||||
s3_bucket.objects[key].public_url(options).to_s
|
||||
end
|
||||
|
||||
def presigned_post(key, options = @@def_opts)
|
||||
s3_bucket.objects[key].presigned_post(options)
|
||||
end
|
||||
|
|
@ -72,8 +76,15 @@ module JamRuby
|
|||
s3_bucket.objects[filename].delete
|
||||
end
|
||||
|
||||
def upload(key, filename)
|
||||
s3_bucket.objects[key].write(:file => filename)
|
||||
def upload(key, filename, options={})
|
||||
options[:file] = filename
|
||||
s3_bucket.objects[key].write(options)
|
||||
end
|
||||
|
||||
def cached_upload(key, filename, options={})
|
||||
options[:file] = filename
|
||||
options.merge({expires: 5.years.from_now})
|
||||
s3_bucket.objects[key].write(filename, options)
|
||||
end
|
||||
|
||||
def delete_folder(folder)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
module JamRuby
|
||||
module S3PublicManagerMixin
|
||||
extend ActiveSupport::Concern
|
||||
include AppConfig
|
||||
|
||||
included do
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
|
||||
end
|
||||
|
||||
def s3_public_manager()
|
||||
@s3_public_manager ||= S3Manager.new(app_config.aws_bucket_public, app_config.aws_access_key_id, app_config.aws_secret_access_key)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -37,6 +37,7 @@ module JamRuby
|
|||
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 :duration, numericality: {only_integer: true}, :allow_nil => true
|
||||
|
||||
validates_format_of :reproduction_royalty_amount, with: /^\d+\.*\d{0,3}$/
|
||||
validates_format_of :licensor_royalty_amount, with: /^\d+\.*\d{0,3}$/
|
||||
|
|
@ -44,7 +45,7 @@ module JamRuby
|
|||
belongs_to :genre, class_name: "JamRuby::Genre"
|
||||
belongs_to :licensor , class_name: 'JamRuby::JamTrackLicensor', foreign_key: 'licensor_id'
|
||||
|
||||
has_many :jam_track_tracks, :class_name => "JamRuby::JamTrackTrack", order: 'position ASC, part ASC, instrument_id ASC'
|
||||
has_many :jam_track_tracks, :class_name => "JamRuby::JamTrackTrack", order: 'track_type ASC, position ASC, part ASC, instrument_id ASC'
|
||||
has_many :jam_track_tap_ins, :class_name => "JamRuby::JamTrackTapIn", order: 'offset_time ASC'
|
||||
|
||||
has_many :jam_track_rights, :class_name => "JamRuby::JamTrackRight" #, inverse_of: 'jam_track', :foreign_key => "jam_track_id" # '
|
||||
|
|
@ -70,7 +71,6 @@ module JamRuby
|
|||
if count.nil?
|
||||
count = 0
|
||||
end
|
||||
puts "count #{count}"
|
||||
counter[track.position] = count + 1
|
||||
end
|
||||
|
||||
|
|
@ -84,6 +84,29 @@ module JamRuby
|
|||
duplicate
|
||||
end
|
||||
|
||||
def missing_previews?
|
||||
missing_preview = false
|
||||
self.jam_track_tracks.each do |track|
|
||||
unless track.has_preview?
|
||||
missing_preview = true
|
||||
break
|
||||
end
|
||||
end
|
||||
missing_preview
|
||||
end
|
||||
|
||||
def onboard_warnings
|
||||
warnings = []
|
||||
warnings << 'POSITIONS' if duplicate_positions?
|
||||
warnings << 'PREVIEWS'if missing_previews?
|
||||
warnings << 'DURATION' if duration.nil?
|
||||
warnings.join(',')
|
||||
end
|
||||
|
||||
def band_jam_track_count
|
||||
JamTrack.where(original_artist: original_artist).count
|
||||
end
|
||||
|
||||
class << self
|
||||
# @return array[artist_name(string)]
|
||||
def all_artists
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ module JamRuby
|
|||
# describes an audio track (like the drums, or guitar) that comprises a JamTrack
|
||||
class JamTrackTrack < ActiveRecord::Base
|
||||
include JamRuby::S3ManagerMixin
|
||||
include JamRuby::S3PublicManagerMixin
|
||||
|
||||
# there should only be one Master per JamTrack, but there can be N Track per JamTrack
|
||||
TRACK_TYPE = %w{Track Master}
|
||||
|
|
@ -41,24 +42,27 @@ 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")
|
||||
# create name of the preview file.
|
||||
# md5-'ed because we cache forever
|
||||
def preview_filename(md5, ext='ogg')
|
||||
original_name = "#{File.basename(self["url_44"], ".ogg")}-preview-#{md5}.#{ext}"
|
||||
"jam_track_previews/#{jam_track.original_artist}/#{jam_track.name}/#{original_name}"
|
||||
end
|
||||
|
||||
def has_preview?
|
||||
!self["preview_url"].nil?
|
||||
!self["preview_url"].nil? && !self['preview_mp3_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})
|
||||
# generates a URL that points to a public version of the preview
|
||||
def preview_public_url(media_type='ogg')
|
||||
url = media_type == 'ogg' ? self[:preview_url] : self[:preview_mp3_url]
|
||||
if url
|
||||
s3_public_manager.public_url(url,{ :secure => false})
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def manually_uploaded_filename(mounted_as)
|
||||
if track_type == 'Master'
|
||||
filename("Master Mix-#{mounted_as == :url_48 ? '48000' : '44100'}.ogg")
|
||||
|
|
@ -67,6 +71,10 @@ module JamRuby
|
|||
end
|
||||
end
|
||||
|
||||
def master?
|
||||
track_type == 'Master'
|
||||
end
|
||||
|
||||
def url_by_sample_rate(sample_rate=48)
|
||||
field_name = (sample_rate==48) ? "url_48" : "url_44"
|
||||
self[field_name]
|
||||
|
|
|
|||
|
|
@ -901,6 +901,11 @@ module JamRuby
|
|||
user.email = user.update_email
|
||||
user.update_email_token = nil
|
||||
user.save
|
||||
begin
|
||||
RecurlyClient.new.update_account(user)
|
||||
rescue Recurly::Error
|
||||
@@log.debug("No recurly account found; continuing")
|
||||
end
|
||||
|
||||
return user
|
||||
end
|
||||
|
|
|
|||
|
|
@ -22,6 +22,11 @@ module JamRuby
|
|||
account
|
||||
end
|
||||
|
||||
def has_account?(current_user)
|
||||
account = get_account(current_user)
|
||||
!!account
|
||||
end
|
||||
|
||||
def delete_account(current_user)
|
||||
account = get_account(current_user)
|
||||
if (account)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
require 'spec_helper'
|
||||
require 'jam_ruby/recurly_client'
|
||||
|
||||
RESET_PASSWORD_URL = "/reset_token"
|
||||
|
||||
|
|
@ -9,6 +10,7 @@ describe User do
|
|||
@user = User.new(first_name: "Example", last_name: "User", email: "user@example.com",
|
||||
password: "foobar", password_confirmation: "foobar", city: "Apex", state: "NC", country: "US", terms_of_service: true, musician: true)
|
||||
@user.musician_instruments << FactoryGirl.build(:musician_instrument, user: @user)
|
||||
@recurly = RecurlyClient.new
|
||||
end
|
||||
|
||||
subject { @user }
|
||||
|
|
@ -434,6 +436,8 @@ describe User do
|
|||
|
||||
describe "finalize email update" do
|
||||
before do
|
||||
@recurly.has_account?(@user).should == false
|
||||
|
||||
@user.begin_update_email("somenewemail@blah.com", "foobar", "http://www.jamkazam.com/confirm_email_update?token=")
|
||||
UserMailer.deliveries.clear
|
||||
end
|
||||
|
|
@ -464,6 +468,36 @@ describe User do
|
|||
end
|
||||
end
|
||||
|
||||
describe "finalize email updates recurly" do
|
||||
before do
|
||||
|
||||
@user.begin_update_email("somenewemail@blah.com", "foobar", "http://www.jamkazam.com/confirm_email_update?token=")
|
||||
UserMailer.deliveries.clear
|
||||
billing_info = {
|
||||
first_name: @user.first_name,
|
||||
last_name: @user.last_name,
|
||||
address1: 'Test Address 1',
|
||||
address2: 'Test Address 2',
|
||||
city: @user.city,
|
||||
state: @user.state,
|
||||
country: @user.country,
|
||||
zip: '12345',
|
||||
number: '4111-1111-1111-1111',
|
||||
month: '08',
|
||||
year: '2017',
|
||||
verification_value: '111'
|
||||
}
|
||||
@recurly.find_or_create_account(@user, billing_info)
|
||||
end
|
||||
|
||||
it "should update recurly" do
|
||||
@recurly.has_account?(@user).should == true
|
||||
@recurly.get_account(@user).email.should_not == "somenewemail@blah.com"
|
||||
@finalized = User.finalize_update_email(@user.update_email_token)
|
||||
@recurly.get_account(@user).email.should == "somenewemail@blah.com"
|
||||
end
|
||||
end
|
||||
|
||||
describe "user_authorizations" do
|
||||
|
||||
it "can create" do
|
||||
|
|
|
|||
|
|
@ -18,11 +18,19 @@
|
|||
var nilOptionStr = '<option value=""></option>';
|
||||
var nilOptionText = 'n/a';
|
||||
var $screen = $('#account-profile-basics');
|
||||
var $avatar = $screen.find('#avatar');
|
||||
var $country = $screen.find('#country');
|
||||
var $region = $screen.find('#region');
|
||||
var $city = $screen.find('#city');
|
||||
var $firstName = $screen.find('#first-name');
|
||||
var $lastName = $screen.find('#last-name');
|
||||
var $gender = $screen.find('#gender');
|
||||
var $biography = $screen.find('#biography');
|
||||
var $subscribe = $screen.find('#subscribe');
|
||||
|
||||
var $btnCancel = $screen.find('#account-edit-profile-cancel');
|
||||
var $btnSubmit = $screen.find('#account-edit-profile-submit');
|
||||
|
||||
var $biography = null;
|
||||
|
||||
function beforeShow(data) {
|
||||
userId = data.id;
|
||||
}
|
||||
|
|
@ -39,27 +47,21 @@
|
|||
}
|
||||
|
||||
function populateAccountProfile(userDetail) {
|
||||
var template = context.JK.fillTemplate($('#template-account-profile-basics').html(), {
|
||||
country: userDetail.country,
|
||||
region: userDetail.state,
|
||||
city: userDetail.city,
|
||||
first_name: userDetail.first_name,
|
||||
last_name: userDetail.last_name,
|
||||
photoUrl: context.JK.resolveAvatarUrl(userDetail.photo_url),
|
||||
birth_date : userDetail.birth_date,
|
||||
gender: userDetail.gender,
|
||||
biography: userDetail.biography ? userDetail.biography : '',
|
||||
subscribe_email: userDetail.subscribe_email ? "checked=checked" : ""
|
||||
});
|
||||
|
||||
$avatar.attr('src', context.JK.resolveAvatarUrl(userDetail.photo_url));
|
||||
$country.val(userDetail.country);
|
||||
$region.val(userDetail.state);
|
||||
$city.val(userDetail.city);
|
||||
$firstName.val(userDetail.first_name);
|
||||
$lastName.val(userDetail.last_name);
|
||||
$gender.val(userDetail.gender);
|
||||
$biography.val(userDetail.biography);
|
||||
|
||||
if (userDetail.subscribe_email) {
|
||||
$subscribe.attr('checked', 'checked');
|
||||
}
|
||||
|
||||
var content_root = $('#account-profile-content-scroller');
|
||||
content_root.html(template);
|
||||
|
||||
$biography = $screen.find('#biography');
|
||||
|
||||
// now use javascript to fix up values too hard to do with templating
|
||||
// set gender
|
||||
$('select[name=gender]', content_root).val(userDetail.gender)
|
||||
|
||||
// set birth_date
|
||||
if(userDetail.birth_date) {
|
||||
|
|
|
|||
|
|
@ -25,18 +25,12 @@
|
|||
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');
|
||||
|
|
@ -102,7 +96,7 @@
|
|||
|
||||
// JamKazam recordings
|
||||
var samples = profileUtils.jamkazamSamples(user.performance_samples);
|
||||
if (samples) {
|
||||
if (samples && samples.length > 0) {
|
||||
$.each(samples, function(index, val) {
|
||||
|
||||
});
|
||||
|
|
@ -110,7 +104,7 @@
|
|||
|
||||
// SoundCloud recordings
|
||||
samples = profileUtils.soundCloudSamples(user.performance_samples);
|
||||
if (samples) {
|
||||
if (samples && samples.length > 0) {
|
||||
$.each(samples, function(index, val) {
|
||||
|
||||
});
|
||||
|
|
@ -118,9 +112,9 @@
|
|||
|
||||
// YouTube videos
|
||||
samples = profileUtils.youTubeSamples(user.performance_samples);
|
||||
if (samples) {
|
||||
if (samples && samples.length > 0) {
|
||||
$.each(samples, function(index, val) {
|
||||
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -137,24 +131,6 @@
|
|||
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);
|
||||
|
|
@ -176,22 +152,8 @@
|
|||
}
|
||||
|
||||
function validate() {
|
||||
// website
|
||||
if ($.trim($website.val()).length > 0) {
|
||||
|
||||
}
|
||||
|
||||
// SoundCloud
|
||||
if ($.trim($soundCloudUsername.val()).length > 0) {
|
||||
|
||||
}
|
||||
|
||||
// ReverbNation
|
||||
if ($.trim($reverbNationUsername.val())) {
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
var errors = $screen.find('.site_validator.error');
|
||||
return !(errors && errors.length > 0);
|
||||
}
|
||||
|
||||
function navigateTo(targetLocation) {
|
||||
|
|
@ -199,7 +161,7 @@
|
|||
}
|
||||
|
||||
function addOnlinePresence(presenceArray, username, type) {
|
||||
if ($.trim($soundCloudUsername.val()).length > 0) {
|
||||
if ($.trim(username).length > 0) {
|
||||
presenceArray.push({
|
||||
service_type: type,
|
||||
username: username
|
||||
|
|
@ -228,17 +190,17 @@
|
|||
// 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);
|
||||
addPerformanceSamples(ps, $jamkazamSampleList, performanceSampleTypes.JAMKAZAM.description);
|
||||
addPerformanceSamples(ps, $soundCloudSampleList, performanceSampleTypes.SOUNDCLOUD.description);
|
||||
addPerformanceSamples(ps, $youTubeSampleList, performanceSampleTypes.YOUTUBE.description);
|
||||
|
||||
// api.updateUser({
|
||||
// website: $website.val(),
|
||||
// online_presences: op,
|
||||
// performance_samples: ps
|
||||
// })
|
||||
// .done(postUpdateProfileSuccess)
|
||||
// .fail(postUpdateProfileFailure);
|
||||
api.updateUser({
|
||||
website: $website.val(),
|
||||
online_presences: op,
|
||||
performance_samples: ps
|
||||
})
|
||||
.done(postUpdateProfileSuccess)
|
||||
.fail(postUpdateProfileFailure);
|
||||
}
|
||||
|
||||
function postUpdateProfileSuccess(response) {
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@
|
|||
//= require jquery.custom-protocol
|
||||
//= require jquery.exists
|
||||
//= require jquery.payment
|
||||
//= require howler.core.js
|
||||
//= require jstz
|
||||
//= require class
|
||||
//= require AAC_underscore
|
||||
|
|
|
|||
|
|
@ -1448,6 +1448,24 @@
|
|||
});
|
||||
}
|
||||
|
||||
function getJamTrack(options) {
|
||||
return $.ajax({
|
||||
type: "GET",
|
||||
url: '/api/jamtracks/' + options['plan_code'] + '?' + $.param(options),
|
||||
dataType: "json",
|
||||
contentType: 'application/json'
|
||||
});
|
||||
}
|
||||
|
||||
function getJamTrackWithArtistInfo(options) {
|
||||
return $.ajax({
|
||||
type: "GET",
|
||||
url: '/api/jamtracks/band/' + options['plan_code'] + '?' + $.param(options),
|
||||
dataType: "json",
|
||||
contentType: 'application/json'
|
||||
});
|
||||
}
|
||||
|
||||
function getJamtracks(options) {
|
||||
return $.ajax({
|
||||
type: "GET",
|
||||
|
|
@ -1769,6 +1787,8 @@
|
|||
this.createDiagnostic = createDiagnostic;
|
||||
this.getLatencyTester = getLatencyTester;
|
||||
this.updateAudioLatency = updateAudioLatency;
|
||||
this.getJamTrack = getJamTrack;
|
||||
this.getJamTrackWithArtistInfo = getJamTrackWithArtistInfo;
|
||||
this.getJamtracks = getJamtracks;
|
||||
this.getPurchasedJamTracks = getPurchasedJamTracks;
|
||||
this.getPaymentHistory = getPaymentHistory;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,125 @@
|
|||
$ = jQuery
|
||||
context = window
|
||||
context.JK ||= {};
|
||||
|
||||
|
||||
context.JK.JamTrackPreview = {}
|
||||
context.JK.JamTrackPreview = class JamTrackPreview
|
||||
constructor: (app, $root, jamTrack, jamTrackTrack, options) ->
|
||||
@EVENTS = context.JK.EVENTS
|
||||
@rest = context.JK.Rest()
|
||||
@logger = context.JK.logger
|
||||
@options = options || {master_shows_duration: false}
|
||||
@app = app
|
||||
@jamTrack = jamTrack
|
||||
@jamTrackTrack = jamTrackTrack
|
||||
@root = $root
|
||||
@playButton = null
|
||||
@stopButton = null
|
||||
@instrumentIcon = null
|
||||
@instrumentName = null
|
||||
@part = null
|
||||
|
||||
template = $('#template-jam-track-preview')
|
||||
throw "no jam track preview template" if not template.exists()
|
||||
|
||||
@root.html($(template.html()))
|
||||
@playButton = @root.find('.play-button')
|
||||
@stopButton = @root.find('.stop-button')
|
||||
@instrumentIcon = @root.find('.instrument-icon')
|
||||
@instrumentName = @root.find('.instrument-name')
|
||||
@part = @root.find('.part')
|
||||
|
||||
@playButton.on('click', @play)
|
||||
@stopButton.on('click', @stop)
|
||||
|
||||
@root.attr('data-track-type', @jamTrackTrack.track_type).attr('data-id', @jamTrackTrack.id)
|
||||
instrumentId = null
|
||||
instrumentDescription = '?'
|
||||
if @jamTrackTrack.track_type == 'Track'
|
||||
if @jamTrackTrack.instrument
|
||||
instrumentId = @jamTrackTrack.instrument.id
|
||||
instrumentDescription = @jamTrackTrack.instrument.description
|
||||
else
|
||||
instrumentId = 'other'
|
||||
instrumentDescription= 'Master Mix'
|
||||
|
||||
instrument_src = context.JK.getInstrumentIcon24(instrumentId)
|
||||
|
||||
@instrumentIcon.attr('data-instrument-id', instrumentId).attr('src', instrument_src)
|
||||
@instrumentName.text(instrumentDescription)
|
||||
#context.JK.bindInstrumentHover(@root)
|
||||
|
||||
part = ''
|
||||
|
||||
if @jamTrackTrack.track_type == 'Track'
|
||||
part = "#{@jamTrackTrack.part}" if @jamTrackTrack.part? && @jamTrackTrack.part != instrumentDescription
|
||||
|
||||
else
|
||||
if @options.master_shows_duration
|
||||
duration = 'entire song'
|
||||
if @jamTrack.duration
|
||||
duration = "0:00 - #{context.JK.prettyPrintSeconds(@jamTrack.duration)}"
|
||||
part = duration
|
||||
else
|
||||
part = @jamTrack.name + ' by ' + @jamTrack.original_artist
|
||||
|
||||
@part.text("(#{part})") if part != ''
|
||||
|
||||
if @jamTrackTrack.preview_mp3_url?
|
||||
|
||||
urls = [@jamTrackTrack.preview_mp3_url]
|
||||
if @jamTrackTrack.preview_ogg_url?
|
||||
urls.push(@jamTrackTrack.preview_ogg_url)
|
||||
|
||||
@no_audio = false
|
||||
@sound = new Howl({
|
||||
src: urls,
|
||||
autoplay: false,
|
||||
loop: false,
|
||||
volume: 1.0,
|
||||
onend: @onHowlerEnd})
|
||||
else
|
||||
@no_audio = true
|
||||
|
||||
if @no_audio
|
||||
@playButton.addClass('disabled')
|
||||
@stopButton.addClass('disabled')
|
||||
|
||||
onHowlerEnd: () =>
|
||||
@logger.debug("on end $(this)", $(this))
|
||||
@stopButton.addClass('hidden')
|
||||
@playButton.removeClass('hidden')
|
||||
|
||||
play: (e) =>
|
||||
if e?
|
||||
e.stopPropagation()
|
||||
|
||||
if @no_audio
|
||||
context.JK.prodBubble(@playButton, 'There is no preview available for this track.', {}, {duration:2000})
|
||||
else
|
||||
logger.debug("play issued for jam track preview")
|
||||
@sound.play()
|
||||
@playButton.addClass('hidden')
|
||||
@stopButton.removeClass('hidden')
|
||||
|
||||
return false
|
||||
|
||||
stop: (e) =>
|
||||
if e?
|
||||
e.stopPropagation()
|
||||
|
||||
if @no_audio
|
||||
context.JK.helpBubble(@playButton, 'There is no preview available for this track.', {}, {duration:2000})
|
||||
else
|
||||
logger.debug("stop issued for jam track preview")
|
||||
@sound.stop()
|
||||
@stopButton.addClass('hidden')
|
||||
@playButton.removeClass('hidden')
|
||||
|
||||
return false
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -18,14 +18,14 @@
|
|||
var COWRITING_GENRE_TYPE = 'cowriting';
|
||||
|
||||
// performance sample types
|
||||
var SAMPLE_TYPES = {
|
||||
profileUtils.SAMPLE_TYPES = {
|
||||
JAMKAZAM: {description: "jamkazam"},
|
||||
SOUNDCLOUD: {description: "soundcloud"},
|
||||
YOUTUBE: {description: "youtube"}
|
||||
};
|
||||
|
||||
// online presence types
|
||||
var ONLINE_PRESENCE_TYPES = {
|
||||
profileUtils.ONLINE_PRESENCE_TYPES = {
|
||||
SOUNDCLOUD: {description: "soundcloud"},
|
||||
REVERBNATION: {description: "reverbnation"},
|
||||
BANDCAMP: {description: "bandcamp"},
|
||||
|
|
@ -184,7 +184,7 @@
|
|||
|
||||
profileUtils.jamkazamSamples = function(samples) {
|
||||
var matches = $.grep(samples, function(s) {
|
||||
return s.service_type === SAMPLE_TYPES.JAMKAZAM.description;
|
||||
return s.service_type === profileUtils.SAMPLE_TYPES.JAMKAZAM.description;
|
||||
});
|
||||
|
||||
return matches;
|
||||
|
|
@ -192,7 +192,7 @@
|
|||
|
||||
profileUtils.soundCloudSamples = function(samples) {
|
||||
var matches = $.grep(samples, function(s) {
|
||||
return s.service_type === SAMPLE_TYPES.SOUNDCLOUD.description;
|
||||
return s.service_type === profileUtils.SAMPLE_TYPES.SOUNDCLOUD.description;
|
||||
});
|
||||
|
||||
return matches;
|
||||
|
|
@ -200,7 +200,7 @@
|
|||
|
||||
profileUtils.youTubeSamples = function(samples) {
|
||||
var matches = $.grep(samples, function(s) {
|
||||
return s.service_type === SAMPLE_TYPES.YOUTUBE.description;
|
||||
return s.service_type === profileUtils.SAMPLE_TYPES.YOUTUBE.description;
|
||||
});
|
||||
|
||||
return matches;
|
||||
|
|
@ -208,7 +208,7 @@
|
|||
|
||||
profileUtils.soundCloudPresences = function(presences) {
|
||||
var matches = $.grep(presences, function(p) {
|
||||
return p.service_type === ONLINE_PRESENCE_TYPES.SOUNDCLOUD.description;
|
||||
return p.service_type === profileUtils.ONLINE_PRESENCE_TYPES.SOUNDCLOUD.description;
|
||||
});
|
||||
|
||||
return matches;
|
||||
|
|
@ -216,7 +216,7 @@
|
|||
|
||||
profileUtils.reverbNationPresences = function(presences) {
|
||||
var matches = $.grep(presences, function(p) {
|
||||
return p.service_type === ONLINE_PRESENCE_TYPES.REVERBNATION.description;
|
||||
return p.service_type === profileUtils.ONLINE_PRESENCE_TYPES.REVERBNATION.description;
|
||||
});
|
||||
|
||||
return matches;
|
||||
|
|
@ -224,7 +224,7 @@
|
|||
|
||||
profileUtils.bandCampPresences = function(presences) {
|
||||
var matches = $.grep(presences, function(p) {
|
||||
return p.service_type === ONLINE_PRESENCE_TYPES.BANDCAMP.description;
|
||||
return p.service_type === profileUtils.ONLINE_PRESENCE_TYPES.BANDCAMP.description;
|
||||
});
|
||||
|
||||
return matches;
|
||||
|
|
@ -232,7 +232,7 @@
|
|||
|
||||
profileUtils.fandalismPresences = function(presences) {
|
||||
var matches = $.grep(presences, function(p) {
|
||||
return p.service_type === ONLINE_PRESENCE_TYPES.FANDALISM.description;
|
||||
return p.service_type === profileUtils.ONLINE_PRESENCE_TYPES.FANDALISM.description;
|
||||
});
|
||||
|
||||
return matches;
|
||||
|
|
@ -240,7 +240,7 @@
|
|||
|
||||
profileUtils.youTubePresences = function(presences) {
|
||||
var matches = $.grep(presences, function(p) {
|
||||
return p.service_type === ONLINE_PRESENCE_TYPES.YOUTUBE.description;
|
||||
return p.service_type === profileUtils.ONLINE_PRESENCE_TYPES.YOUTUBE.description;
|
||||
});
|
||||
|
||||
return matches;
|
||||
|
|
@ -248,7 +248,7 @@
|
|||
|
||||
profileUtils.facebookPresences = function(presences) {
|
||||
var matches = $.grep(presences, function(p) {
|
||||
return p.service_type === ONLINE_PRESENCE_TYPES.FACEBOOK.description;
|
||||
return p.service_type === profileUtils.ONLINE_PRESENCE_TYPES.FACEBOOK.description;
|
||||
});
|
||||
|
||||
return matches;
|
||||
|
|
@ -256,7 +256,7 @@
|
|||
|
||||
profileUtils.twitterPresences = function(presences) {
|
||||
var matches = $.grep(presences, function(p) {
|
||||
return p.service_type === ONLINE_PRESENCE_TYPES.TWITTER.description;
|
||||
return p.service_type === profileUtils.ONLINE_PRESENCE_TYPES.TWITTER.description;
|
||||
});
|
||||
|
||||
return matches;
|
||||
|
|
|
|||
|
|
@ -2740,6 +2740,12 @@
|
|||
logger.debug("Unstable clocks: ", names, unstable)
|
||||
context.JK.Banner.showAlert("Couldn't open metronome", context._.template($('#template-help-metronome-unstable').html(), {names: names}, { variable: 'data' }));
|
||||
} else {
|
||||
var data = {
|
||||
value: 1,
|
||||
session_size: sessionModel.participants().length,
|
||||
user_id: context.JK.currentUserId,
|
||||
user_name: context.JK.currentUserName }
|
||||
context.stats.write('web.metronome.open', data)
|
||||
var bpm = 120;
|
||||
logger.debug("opening the metronome with bpm: " + bpm + ", sound:" + metroSound)
|
||||
rest.openMetronome({id: sessionModel.id()})
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ context.JK.SiteValidator = class SiteValidator
|
|||
@fail_callback(@input_div)
|
||||
|
||||
@deferred_status_check = null
|
||||
@logger.debug("site_status = "+@site_status)
|
||||
@logger.debug("site_status = " + @site_status)
|
||||
|
||||
processSiteCheckFail: (response) =>
|
||||
@logger.error("site check error")
|
||||
|
|
@ -130,10 +130,12 @@ context.JK.SiteValidator = class SiteValidator
|
|||
|
||||
context.JK.RecordingSourceValidator = class RecordingSourceValidator extends SiteValidator
|
||||
constructor: (site_type, success_callback, fail_callback) ->
|
||||
super(site_type, success_callback, fail_callback)
|
||||
super(site_type)
|
||||
@recording_sources = []
|
||||
@is_rec_src = true
|
||||
@add_btn = @input_div.find('a.add-recording-source')
|
||||
@site_success_callback = success_callback
|
||||
@site_fail_callback = fail_callback
|
||||
|
||||
init: (sources) =>
|
||||
super()
|
||||
|
|
@ -145,11 +147,17 @@ context.JK.RecordingSourceValidator = class RecordingSourceValidator extends Sit
|
|||
processSiteCheckSucceed: (response) =>
|
||||
super(response)
|
||||
@add_btn.removeClass('disabled')
|
||||
@recording_sources.push({ url: response.data, recording_id: response.recording_id })
|
||||
|
||||
if @site_status
|
||||
@recording_sources.push({ url: response.data, recording_id: response.recording_id })
|
||||
if @site_success_callback
|
||||
@site_success_callback(@input_div)
|
||||
|
||||
processSiteCheckFail: (response) =>
|
||||
super(response)
|
||||
@add_btn.removeClass('disabled')
|
||||
if @site_fail_callback
|
||||
@site_fail_callback(@input_div)
|
||||
|
||||
didBlur: () =>
|
||||
# do nothing, validate on add only
|
||||
|
|
@ -174,3 +182,6 @@ context.JK.RecordingSourceValidator = class RecordingSourceValidator extends Sit
|
|||
src_data['url'] == url
|
||||
0 < vals.length
|
||||
|
||||
recordingSources: () =>
|
||||
@recording_sources
|
||||
|
||||
|
|
|
|||
|
|
@ -133,12 +133,17 @@
|
|||
}
|
||||
}
|
||||
else {
|
||||
var $template = $('#template-help-' + templateName)
|
||||
if($template.length == 0) {
|
||||
var helpText = templateName;
|
||||
try {
|
||||
var $template = $('#template-help-' + templateName)
|
||||
if ($template.length == 0) {
|
||||
var helpText = templateName;
|
||||
}
|
||||
else {
|
||||
var helpText = context._.template($template.html(), data, { variable: 'data' });
|
||||
}
|
||||
}
|
||||
else {
|
||||
var helpText = context._.template($template.html(), data, { variable: 'data' });
|
||||
catch(e) {
|
||||
var helpText = templateName;
|
||||
}
|
||||
|
||||
holder = $('<div class="hover-bubble help-bubble"></div>');
|
||||
|
|
|
|||
|
|
@ -0,0 +1,62 @@
|
|||
(function (context, $) {
|
||||
|
||||
"use strict";
|
||||
|
||||
context.JK = context.JK || {};
|
||||
context.JK.IndividualJamTrack = function (app) {
|
||||
|
||||
var rest = context.JK.Rest();
|
||||
var logger = context.JK.logger;
|
||||
var $page = null;
|
||||
var $jamtrack_name = null;
|
||||
var $previews = null;
|
||||
var $jamTracksButton = null;
|
||||
var $genericHeader = null;
|
||||
var $individualizedHeader = null;
|
||||
|
||||
function fetchJamTrack() {
|
||||
rest.getJamTrack({plan_code: gon.jam_track_plan_code})
|
||||
.done(function (jam_track) {
|
||||
logger.debug("jam_track", jam_track)
|
||||
|
||||
if(!gon.just_previews) {
|
||||
if (gon.generic) {
|
||||
$genericHeader.removeClass('hidden');
|
||||
}
|
||||
else {
|
||||
$individualizedHeader.removeClass('hidden')
|
||||
$jamtrack_name.text(jam_track.name);
|
||||
$jamTracksButton.attr('href', '/client?artist=' + jam_track.original_artist + '#/jamtrack')
|
||||
}
|
||||
}
|
||||
|
||||
context._.each(jam_track.tracks, function (track) {
|
||||
|
||||
var $element = $('<div class="jam-track-preview-holder"></div>')
|
||||
|
||||
$previews.append($element);
|
||||
|
||||
new context.JK.JamTrackPreview(app, $element, jam_track, track, {master_shows_duration: false})
|
||||
})
|
||||
|
||||
$previews.append('<br clear = "all" />')
|
||||
})
|
||||
.fail(function () {
|
||||
app.notify({title: 'Unable to fetch JamTrack', text: "Please refresh the page or try again later."})
|
||||
})
|
||||
|
||||
}
|
||||
function initialize() {
|
||||
|
||||
$page = $('body')
|
||||
$jamtrack_name = $page.find('.jamtrack_name')
|
||||
$previews = $page.find('.previews')
|
||||
$jamTracksButton = $page.find('.browse-jamtracks-wrapper .white-bordered-button')
|
||||
$genericHeader = $page.find('h1.generic')
|
||||
$individualizedHeader = $page.find('h1.individualized')
|
||||
fetchJamTrack();
|
||||
}
|
||||
|
||||
this.initialize = initialize;
|
||||
}
|
||||
})(window, jQuery);
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
|
||||
(function (context, $) {
|
||||
|
||||
"use strict";
|
||||
|
||||
context.JK = context.JK || {};
|
||||
context.JK.IndividualJamTrackBand = function (app) {
|
||||
|
||||
var rest = context.JK.Rest();
|
||||
var logger = context.JK.logger;
|
||||
var $page = null;
|
||||
var $jamTrackBandInfo = null;
|
||||
var $jamTrackNoun = null;
|
||||
var $previews = null;
|
||||
var $jamTracksButton = null;
|
||||
var $checkItOut = null;
|
||||
|
||||
function fetchJamTrack() {
|
||||
rest.getJamTrackWithArtistInfo({plan_code: gon.jam_track_plan_code})
|
||||
.done(function (jam_track) {
|
||||
logger.debug("jam_track", jam_track)
|
||||
|
||||
$jamTrackBandInfo.text(jam_track.band_jam_track_count + ' ' + jam_track.original_artist);
|
||||
$jamTracksButton.attr('href', '/client?artist=' + jam_track.original_artist + '#/jamtrack')
|
||||
|
||||
if(jam_track.band_jam_track_count == 1) {
|
||||
$jamTrackNoun.text('JamTrack')
|
||||
$checkItOut.text(', Check It Out!')
|
||||
}
|
||||
context._.each(jam_track.tracks, function (track) {
|
||||
|
||||
var $element = $('<div class="jam-track-preview-holder"></div>')
|
||||
|
||||
$previews.append($element);
|
||||
|
||||
new context.JK.JamTrackPreview(app, $element, jam_track, track, {master_shows_duration: false})
|
||||
})
|
||||
|
||||
$previews.append('<br clear = "all" />')
|
||||
})
|
||||
.fail(function () {
|
||||
app.notify({title: 'Unable to fetch JamTrack', text: "Please refresh the page or try again later."})
|
||||
})
|
||||
|
||||
}
|
||||
function initialize() {
|
||||
|
||||
$page = $('body')
|
||||
$jamTrackBandInfo = $page.find('.jamtrack_band_info')
|
||||
$previews = $page.find('.previews')
|
||||
$jamTracksButton = $page.find('.browse-jamtracks-wrapper .white-bordered-button')
|
||||
$jamTrackNoun = $page.find('.jamtrack_noun')
|
||||
$checkItOut = $page.find('.check-it-out')
|
||||
|
||||
fetchJamTrack();
|
||||
}
|
||||
|
||||
this.initialize = initialize;
|
||||
}
|
||||
})(window, jQuery);
|
||||
|
|
@ -20,6 +20,7 @@
|
|||
//= require jquery.icheck
|
||||
//= require jquery.bt
|
||||
//= require jquery.exists
|
||||
//= require howler.core.js
|
||||
//= require AAA_Log
|
||||
//= require AAC_underscore
|
||||
//= require alert
|
||||
|
|
@ -52,6 +53,7 @@
|
|||
//= require recording_utils
|
||||
//= require helpBubbleHelper
|
||||
//= require facebook_rest
|
||||
//= require jam_track_preview
|
||||
//= require landing/init
|
||||
//= require landing/signup
|
||||
//= require web/downloads
|
||||
|
|
@ -60,6 +62,8 @@
|
|||
//= require web/session_info
|
||||
//= require web/recordings
|
||||
//= require web/welcome
|
||||
//= require web/individual_jamtrack
|
||||
//= require web/individual_jamtrack_band
|
||||
//= require fakeJamClient
|
||||
//= require fakeJamClientMessages
|
||||
//= require fakeJamClientRecordings
|
||||
|
|
|
|||
|
|
@ -31,8 +31,11 @@
|
|||
}
|
||||
}
|
||||
|
||||
.sample-list {
|
||||
|
||||
div.sample-list {
|
||||
height: 250px;
|
||||
width: 250px;
|
||||
border: 2px solid #ccc;
|
||||
overflow: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -73,4 +73,5 @@
|
|||
*= require icheck/minimal/minimal
|
||||
*= require users/syncViewer
|
||||
*= require ./downloadJamTrack
|
||||
*= require ./jamTrackPreview
|
||||
*/
|
||||
|
|
@ -318,3 +318,15 @@ $fair: #cc9900;
|
|||
}
|
||||
}
|
||||
|
||||
.white-bordered-button {
|
||||
font-size:20px;
|
||||
font-weight:bold;
|
||||
background-color:white;
|
||||
color:$ColorScreenPrimary;
|
||||
border:3px solid $ColorScreenPrimary;
|
||||
padding:18px;
|
||||
-webkit-border-radius:8px;
|
||||
-moz-border-radius:8px;
|
||||
border-radius:8px;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
@import "client/common";
|
||||
|
||||
.jam-track-preview {
|
||||
|
||||
display:inline-block;
|
||||
line-height:24px;
|
||||
vertical-align: middle;
|
||||
@include border_box_sizing;
|
||||
color:$ColorTextTypical;
|
||||
font-size:14px;
|
||||
|
||||
.actions {
|
||||
display:inline;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
img.instrument-icon {
|
||||
display:inline;
|
||||
vertical-align: middle;
|
||||
margin-left:10px;
|
||||
}
|
||||
|
||||
.instrument-name {
|
||||
display:inline;
|
||||
vertical-align: middle;
|
||||
margin-left:10px;
|
||||
|
||||
}
|
||||
|
||||
.part {
|
||||
display:inline;
|
||||
vertical-align: middle;
|
||||
margin-left:4px;
|
||||
}
|
||||
}
|
||||
|
|
@ -134,7 +134,7 @@ input[type="button"] {
|
|||
}
|
||||
|
||||
.hidden {
|
||||
display:none;
|
||||
display:none !important;
|
||||
}
|
||||
|
||||
.small {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
body.web.landing_jamtrack.individual_jamtrack {
|
||||
|
||||
.previews {
|
||||
margin-top:10px;
|
||||
}
|
||||
.jamtrack-reasons {
|
||||
margin: 10px 0 0 20px;
|
||||
}
|
||||
|
||||
.white-bordered-button {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.browse-jamtracks-wrapper {
|
||||
text-align:center;
|
||||
width:90%;
|
||||
}
|
||||
|
||||
.jam-track-preview-holder {
|
||||
|
||||
margin-bottom: 7px;
|
||||
float: left;
|
||||
|
||||
&[data-track-type="Master"] {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&[data-track-type="Track"] {
|
||||
width: 50%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
body.web.landing_jamtrack.individual_jamtrack_band {
|
||||
|
||||
.previews {
|
||||
margin-top:10px;
|
||||
}
|
||||
.jamtrack-reasons {
|
||||
margin: 10px 0 0 20px;
|
||||
}
|
||||
|
||||
.white-bordered-button {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.browse-jamtracks-wrapper {
|
||||
text-align:center;
|
||||
width:90%;
|
||||
}
|
||||
|
||||
.jam-track-preview-holder {
|
||||
|
||||
margin-bottom: 7px;
|
||||
float: left;
|
||||
|
||||
&[data-track-type="Master"] {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&[data-track-type="Track"] {
|
||||
width: 50%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
@import "client/common.css.scss";
|
||||
|
||||
body.web.landing_page {
|
||||
|
||||
.two_by_two {
|
||||
|
||||
h1 {
|
||||
margin:0 0 5px;
|
||||
padding:7px 0;
|
||||
display:inline-block;
|
||||
}
|
||||
.row {
|
||||
@include border_box_sizing;
|
||||
|
||||
&:nth-of-type(1) {
|
||||
padding:20px 0 0 0;
|
||||
}
|
||||
|
||||
|
||||
.column {
|
||||
width:50%;
|
||||
float:left;
|
||||
@include border_box_sizing;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.landing_jamtrack, &.landing_product {
|
||||
|
||||
.landing-tag {
|
||||
left:50%;
|
||||
text-align:center;
|
||||
}
|
||||
p, ul, li {
|
||||
font-size:14px;
|
||||
line-height:125%;
|
||||
color:$ColorTextTypical;
|
||||
}
|
||||
p {
|
||||
|
||||
}
|
||||
ul {
|
||||
list-style-type: disc;
|
||||
}
|
||||
li {
|
||||
margin-left:20px;
|
||||
}
|
||||
.video-container {
|
||||
margin-top:0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
@import "client/common.css.scss";
|
||||
|
||||
body.web.landing_product {
|
||||
|
||||
h1.product-headline {
|
||||
color:white;
|
||||
background-color:$ColorScreenPrimary;
|
||||
margin-bottom:20px;
|
||||
padding:7px;
|
||||
border-radius:4px;
|
||||
}
|
||||
|
||||
.product-description {
|
||||
margin-bottom:20px;
|
||||
}
|
||||
|
||||
.white-bordered-button {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.cta-big-button {
|
||||
text-align:center;
|
||||
width:90%;
|
||||
}
|
||||
|
||||
.linked-video-holder {
|
||||
text-align:center;
|
||||
width:90%;
|
||||
margin-top:20px;
|
||||
}
|
||||
|
||||
.previews {
|
||||
margin-top:10px;
|
||||
}
|
||||
|
||||
.jamtrack-reasons {
|
||||
margin-top:20px;
|
||||
}
|
||||
|
||||
.jam-track-preview-holder {
|
||||
|
||||
margin-bottom: 7px;
|
||||
float: left;
|
||||
|
||||
&[data-track-type="Master"] {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&[data-track-type="Track"] {
|
||||
width: 50%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
*= require client/jamServer
|
||||
*= require client/ie
|
||||
*= require client/jamkazam
|
||||
*= require jquery.bt
|
||||
*= require easydropdown
|
||||
*= require easydropdown_jk
|
||||
*= require client/screen_common
|
||||
|
|
@ -14,6 +15,7 @@
|
|||
*= require client/help
|
||||
*= require client/listenBroadcast
|
||||
*= require client/flash
|
||||
*= require client/jamTrackPreview
|
||||
*= require web/main
|
||||
*= require web/footer
|
||||
*= require web/recordings
|
||||
|
|
@ -24,6 +26,7 @@
|
|||
*= require web/downloads
|
||||
*= require users/signinCommon
|
||||
*= require dialogs/dialog
|
||||
*= require landings/landing_page
|
||||
*= require client/help
|
||||
*= require_directory ../landings
|
||||
*= require icheck/minimal/minimal
|
||||
*/
|
||||
|
|
@ -1,12 +1,20 @@
|
|||
class ApiJamTracksController < ApiController
|
||||
|
||||
# have to be signed in currently to see this screen
|
||||
before_filter :api_signed_in_user, :except => [:index]
|
||||
before_filter :api_any_user, :only => [:index]
|
||||
before_filter :api_signed_in_user, :except => [:index, :show, :show_with_artist_info]
|
||||
before_filter :api_any_user, :only => [:index, :show, :show_with_artist_info]
|
||||
before_filter :lookup_jam_track_right, :only => [:download,:enqueue, :show_jam_track_right]
|
||||
|
||||
respond_to :json
|
||||
|
||||
def show
|
||||
@jam_track = JamTrack.find_by_plan_code!(params[:plan_code])
|
||||
end
|
||||
|
||||
def show_with_artist_info
|
||||
@jam_track = JamTrack.find_by_plan_code!(params[:plan_code])
|
||||
end
|
||||
|
||||
def index
|
||||
data = JamTrack.index(params, any_user)
|
||||
@jam_tracks, @next = data[0], data[1]
|
||||
|
|
|
|||
|
|
@ -65,5 +65,37 @@ class LandingsController < ApplicationController
|
|||
def watch_overview_tight
|
||||
render 'watch_overview_tight', layout: 'web'
|
||||
end
|
||||
|
||||
def individual_jamtrack
|
||||
gon.jam_track_plan_code = params[:plan_code] ? "jamtrack-" + params[:plan_code] : nil
|
||||
gon.generic = params[:generic]
|
||||
render 'individual_jamtrack', layout: 'web'
|
||||
end
|
||||
|
||||
def individual_jamtrack_band
|
||||
gon.jam_track_plan_code = params[:plan_code] ? "jamtrack-" + params[:plan_code] : nil
|
||||
|
||||
render 'individual_jamtrack_band', layout: 'web'
|
||||
end
|
||||
|
||||
def product_jamblaster
|
||||
render 'product_jamblaster', layout: 'web'
|
||||
end
|
||||
|
||||
def product_platform
|
||||
render 'product_platform', layout: 'web'
|
||||
end
|
||||
|
||||
def product_jamtracks
|
||||
gon.generic = true
|
||||
gon.just_previews = true
|
||||
jam_track = JamTrack.select('plan_code').where(plan_code: Rails.application.config.nominated_jam_track).first
|
||||
unless jam_track
|
||||
jam_track = JamTrack.first
|
||||
end
|
||||
|
||||
gon.jam_track_plan_code = jam_track.plan_code
|
||||
render 'product_jamtracks', layout: 'web'
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -53,6 +53,13 @@ class SpikesController < ApplicationController
|
|||
render :layout => 'web'
|
||||
end
|
||||
|
||||
def jam_track_preview
|
||||
gon.jamTrackPlanCode = params[:plan_code]
|
||||
|
||||
|
||||
render :layout => 'web'
|
||||
end
|
||||
|
||||
def site_validate
|
||||
render :layout => 'web'
|
||||
end
|
||||
|
|
|
|||
|
|
@ -16,6 +16,13 @@ end
|
|||
|
||||
child(:jam_track_tracks => :tracks) {
|
||||
attributes :id, :part, :instrument, :track_type
|
||||
|
||||
node do |track|
|
||||
{
|
||||
preview_mp3_url: track.preview_public_url('mp3'),
|
||||
preview_ogg_url: track.preview_public_url('ogg')
|
||||
}
|
||||
end
|
||||
}
|
||||
|
||||
child(:licensor => :licensor) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
object @jam_track
|
||||
|
||||
attributes :band_jam_track_count
|
||||
|
||||
node do |jam_track|
|
||||
partial "api_jam_tracks/show", object: @jam_track
|
||||
end
|
||||
|
|
@ -1,105 +1,98 @@
|
|||
<!-- Account Profile Screen -->
|
||||
<div layout="screen" id="account-profile-basics" layout-id="account/profile" class="screen secondary">
|
||||
<!-- header -->
|
||||
|
||||
<div class="content-head">
|
||||
<!-- icon -->
|
||||
|
||||
<div class="content-icon">
|
||||
<%= image_tag "content/icon_account.png", {:width => 27, :height => 20} %>
|
||||
</div>
|
||||
<!-- section head text -->
|
||||
|
||||
<h1>my account</h1>
|
||||
<%= render "screen_navigation" %>
|
||||
</div>
|
||||
<!-- end header -->
|
||||
|
||||
<!-- profile scrolling area -->
|
||||
<div class="content-body">
|
||||
<div id="account-profile-content-scroller" class="content-body-scroller account-content-scroller">
|
||||
|
||||
<div class="content-wrapper account-profile">
|
||||
|
||||
<form id="account-edit-profile-form">
|
||||
|
||||
<h2>edit profile: basics</h2>
|
||||
<br /><br />
|
||||
<div class="location w25 left">
|
||||
<a href="#" class="avatar_large"><img id="avatar" /></a>
|
||||
<a href="#" class="small" id="account-change-avatar">Change Avatar</a>
|
||||
<div class="clearall"></div>
|
||||
|
||||
<div class="field">
|
||||
<label>Country:</label>
|
||||
<select id="country" name='country' class="w80">
|
||||
<option selected="selected"></option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label>State/Province:</label>
|
||||
<select id="region" name='region' class="w80" disabled='disabled'>
|
||||
<option selected="selected"></option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label>City:</label>
|
||||
<select id="city" name='city' class="w80" disabled='disabled'>
|
||||
<option selected="selected"></option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="right-side right w70" style="margin-top:-36px;">
|
||||
<div class="field left w45">
|
||||
<label>First Name:</label>
|
||||
<input type="text" id="first-name" name="first_name" class="w70" style="margin-bottom:12px;">
|
||||
</div>
|
||||
<div class="field left w45">
|
||||
<label>Last Name:</label>
|
||||
<input type="text" id="last-name" name="last_name" class="w70" style="margin-bottom:12px;">
|
||||
</div>
|
||||
|
||||
<br class="clearall"/>
|
||||
|
||||
<div class="field left w45 gender">
|
||||
<label>Gender:</label>
|
||||
<select id="gender" name="gender" class="w80">
|
||||
<option value='M'>Male</option>
|
||||
<option value='F'>Female</option>
|
||||
<option>-</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="field left w45 birth_date">
|
||||
<label>Birth Date:</label>
|
||||
<%= date_select("user", "birth_date", :use_short_month => true, :start_year => 1900, :end_year => Time.now.year - 18, :order => [:month, :day, :year], :default => -25.years.from_now, :html=>{:class => "account-profile-birthdate"} ) %>
|
||||
</div>
|
||||
|
||||
<br class="clearall"/>
|
||||
|
||||
<div class="field">
|
||||
<label>Musical Bio:</label>
|
||||
<textarea id="biography" name="biography" class="biography"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<input type="checkbox" id="subscribe" name="subscribe_email" /> I will accept email from JamKazam about this service.
|
||||
</div>
|
||||
|
||||
<div class="right field actions">
|
||||
<a id="account-edit-profile-cancel" class="button-grey">CANCEL</a> <a id="account-edit-profile-submit" class="button-orange">SAVE & NEXT</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="clearall"></div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- end content scrolling area -->
|
||||
</div>
|
||||
|
||||
<script type="text/template" id="template-account-profile-basics">
|
||||
<!-- content wrapper -->
|
||||
<div class="content-wrapper account-profile">
|
||||
|
||||
<form id="account-edit-profile-form">
|
||||
|
||||
<h2>edit profile: basics</h2>
|
||||
<br /><br />
|
||||
<div class="location w25 left">
|
||||
<a href="#" class="avatar_large"><img src="{photoUrl}" id="profile-avatar" /></a>
|
||||
<a href="#" class="small" id="account-change-avatar">Change Avatar</a>
|
||||
<div class="clearall"></div>
|
||||
|
||||
<div class="field">
|
||||
<label>Country:</label>
|
||||
<select name='country' class="w80">
|
||||
<option value='{country}' selected="selected">{country}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label>State/Province:</label>
|
||||
<select name='region' class="w80" disabled='disabled'>
|
||||
<option value="{region}" selected="selected">{region}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label>City:</label>
|
||||
<select name='city' class="w80" disabled='disabled'>
|
||||
<option value="{city}" selected="selected">{city}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="right-side right w70" style="margin-top:-36px;">
|
||||
<div class="field left w45">
|
||||
<label>First Name:</label>
|
||||
<input type="text" name="first_name" value="{first_name}" class="w70" style="margin-bottom:12px;">
|
||||
</div>
|
||||
<div class="field left w45">
|
||||
<label>Last Name:</label>
|
||||
<input type="text" name="last_name" value="{last_name}" class="w70" style="margin-bottom:12px;">
|
||||
</div>
|
||||
|
||||
<br class="clearall"/>
|
||||
|
||||
<div class="field left w45 gender">
|
||||
<label>Gender:</label>
|
||||
<select name="gender" data-value="{gender}" class="w80">
|
||||
<option value='M'>Male</option>
|
||||
<option value='F'>Female</option>
|
||||
<option>-</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="field left w45 birth_date">
|
||||
<label>Birth Date:</label>
|
||||
<%= date_select("user", "birth_date", :use_short_month => true, :start_year => 1900, :end_year => Time.now.year - 18, :order => [:month, :day, :year], :default => -25.years.from_now, :html=>{:class => "account-profile-birthdate"} ) %>
|
||||
</div>
|
||||
|
||||
<br class="clearall"/>
|
||||
|
||||
<div class="field">
|
||||
<label>Musical Bio:</label>
|
||||
<textarea id="biography" name="biography" class="biography">{biography}</textarea>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<input type="checkbox" name="subscribe_email" {subscribe_email} /> I will accept email from JamKazam about this service.
|
||||
</div>
|
||||
|
||||
<div class="right field actions">
|
||||
<a id="account-edit-profile-cancel" href="#" class="button-grey">CANCEL</a> <a id="account-edit-profile-submit" href="#" class="button-orange">SAVE & NEXT</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="clearall"/>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -74,21 +74,18 @@
|
|||
<hr>
|
||||
|
||||
<div>
|
||||
|
||||
<div class="left samples jamkazam">
|
||||
<label>JamKazam Recordings:</label>
|
||||
<div class="left">
|
||||
<a id="btn-add-jk-recording" class="button-grey">BROWSE</a>
|
||||
</div>
|
||||
<div class="clearall"></div>
|
||||
<div class="clearall"></div><br/>
|
||||
<div class="sample-list">
|
||||
<table>
|
||||
<tr data-attr-id='12345' data-attr-name='Test Recording' data-attr-url="http://test.url">
|
||||
<td>Test Recording</td>
|
||||
<td>X</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="left samples soundcloud">
|
||||
<label>SoundCloud Recordings (URL):</label>
|
||||
<div id="rec_soundcloud_validator" class="left sample site_validator">
|
||||
|
|
@ -98,14 +95,10 @@
|
|||
</div>
|
||||
<div class="clearall"></div>
|
||||
<div class="sample-list">
|
||||
<table>
|
||||
<tr data-attr-id='12345' data-attr-name='Test Recording' data-attr-url="http://test.url">
|
||||
<td>Test Recording</td>
|
||||
<td>X</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="left samples youtube">
|
||||
<label>YouTube Videos (URL):</label>
|
||||
<div id="rec_youtube_validator" class="left sample site_validator">
|
||||
|
|
@ -115,22 +108,18 @@
|
|||
</div>
|
||||
<div class="clearall"></div>
|
||||
<div class="sample-list">
|
||||
<table>
|
||||
<tr data-attr-id='12345' data-attr-name='Test Recording' data-attr-url="http://test.url">
|
||||
<td>Test Recording</td>
|
||||
<td>X</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="clearall"></div>
|
||||
<br/><br/>
|
||||
|
||||
<div class="right field actions">
|
||||
<a id="account-edit-profile-cancel" class="button-grey">CANCEL</a>
|
||||
<a id="account-edit-profile-back" class="button-grey">BACK</a>
|
||||
<a id="account-edit-profile-cancel" class="button-grey">CANCEL</a>
|
||||
<a id="account-edit-profile-back" class="button-grey">BACK</a>
|
||||
<a id="account-edit-profile-submit" class="button-orange">SAVE & FINISH</a>
|
||||
</div>
|
||||
|
||||
|
|
@ -152,6 +141,12 @@
|
|||
}
|
||||
initialized = true;
|
||||
|
||||
var $screen = $('#account-profile-samples');
|
||||
var $btnAddSoundCloudRecording = $screen.find('#btn-add-soundcloud-recording');
|
||||
var $btnAddYouTubeVideo = $screen.find('#btn-add-youtube-video');
|
||||
var $soundCloudSampleList = $screen.find('.samples.soundcloud');
|
||||
var $youTubeSampleList = $screen.find('.samples.youtube');
|
||||
|
||||
setTimeout(function() {
|
||||
window.urlValidator = new JK.SiteValidator('url', userNameSuccessCallback, userNameFailCallback);
|
||||
urlValidator.init();
|
||||
|
|
@ -177,10 +172,10 @@
|
|||
window.twitterValidator = new JK.SiteValidator('twitter', userNameSuccessCallback, userNameFailCallback);
|
||||
twitterValidator.init();
|
||||
|
||||
window.soundCloudRecordingValidator = new JK.SiteValidator('rec_soundcloud', userNameSuccessCallback, userNameFailCallback);
|
||||
window.soundCloudRecordingValidator = new JK.RecordingSourceValidator('rec_soundcloud', siteSuccessCallback, siteFailCallback);
|
||||
soundCloudRecordingValidator.init();
|
||||
|
||||
window.youTubeRecordingValidator = new JK.SiteValidator('rec_youtube', userNameSuccessCallback, userNameFailCallback);
|
||||
window.youTubeRecordingValidator = new JK.RecordingSourceValidator('rec_youtube', siteSuccessCallback, siteFailCallback);
|
||||
youTubeRecordingValidator.init();
|
||||
}, 1);
|
||||
|
||||
|
|
@ -198,6 +193,18 @@
|
|||
function siteSuccessCallback($inputDiv) {
|
||||
$inputDiv.removeClass('error');
|
||||
$inputDiv.find('.error-text').remove();
|
||||
|
||||
var recordingSources = window.soundCloudRecordingValidator.recordingSources();
|
||||
if (recordingSources && recordingSources.length > 0) {
|
||||
console.log('recordingSources=%o', recordingSources);
|
||||
var $sampleList = $soundCloudSampleList.find('.sample-list');
|
||||
var addedRecording = recordingSources[recordingSources.length-1];
|
||||
$sampleList.append('<div class="recording-row left" data-recording-id="' + addedRecording.recording_id + '">');
|
||||
$sampleList.append(addedRecording.url);
|
||||
$sampleList.append('</div>');
|
||||
}
|
||||
|
||||
$inputDiv.find('input').val('');
|
||||
}
|
||||
|
||||
function siteFailCallback($inputDiv) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
script type="text/template" id='template-jam-track-preview'
|
||||
.jam-track-preview
|
||||
.actions
|
||||
a.play-button href="#"
|
||||
| Play
|
||||
a.stop-button.hidden href="#"
|
||||
| Stop
|
||||
img.instrument-icon hoveraction="instrument" data-instrument-id="" width="24" height="24"
|
||||
.instrument-name
|
||||
.part
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
#jamtrackLanding.screen.secondary layout='screen' layout-id='jamtrackLanding'
|
||||
#jamtrackLanding.screen.secondary.no-login-required layout='screen' layout-id='jamtrackLanding'
|
||||
.content
|
||||
.content-head
|
||||
.content-icon=image_tag("content/icon_jamtracks.png", height:19, width:19)
|
||||
|
|
|
|||
|
|
@ -73,6 +73,7 @@
|
|||
<%= render "listenBroadcast" %>
|
||||
<%= render "sync_viewer_templates" %>
|
||||
<%= render "download_jamtrack_templates" %>
|
||||
<%= render "jam_track_preview" %>
|
||||
<%= render "help" %>
|
||||
<%= render 'dialogs/dialogs' %>
|
||||
<div id="fb-root"></div>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,48 @@
|
|||
- provide(:page_name, 'landing_page full landing_jamtrack individual_jamtrack')
|
||||
|
||||
.two_by_two
|
||||
.row
|
||||
.column
|
||||
h1.hidden.individualized
|
||||
| Check Out Our
|
||||
strong.jamtrack_name
|
||||
| JamTrack
|
||||
h1.hidden.generic
|
||||
| We Have 100+ Amazing JamTracks, Check One Out!
|
||||
p Click the play buttons below to hear the master mix and each fully isolated track. All are included in each single JamTrack.
|
||||
.previews
|
||||
.column
|
||||
h1 See What You Can Do With JamTracks
|
||||
.video-wrapper
|
||||
.video-container
|
||||
iframe src="//www.youtube.com/embed/gAJAIHMyois" frameborder="0" allowfullscreen
|
||||
br clear="all"
|
||||
.row
|
||||
.column
|
||||
h1
|
||||
| Get Your First JamTrack Free Now!
|
||||
p Click the GET A JAMTRACK FREE button below. Browse to find the one you want. Click Add to cart, and we'll apply a credit during checkout to make this first one free! We're confident you'll be back for more.
|
||||
.browse-jamtracks-wrapper
|
||||
a.white-bordered-button href="/client#/jamtrack" GET A JAMTRACK FREE!
|
||||
.column
|
||||
h1 Why Are JamTracks Different & Better?
|
||||
p
|
||||
| JamTracks are the best way to play with your favorite music.
|
||||
| Unlike traditional backing tracks, JamTracks are complete multitrack recordings,
|
||||
| with fully isolated tracks for each part. Used with the free JamKazam app/service, you can:
|
||||
ul.jamtrack-reasons
|
||||
li Solo just the individual track you want to play to hear and learn it
|
||||
li Mute just the track you want to play, and play along with the rest
|
||||
li Make audio recordings and share them via Facebook or URL
|
||||
li Make video recordings and share them via YouTube or URL
|
||||
li And even go online to play JamTracks with others in real time!
|
||||
br clear="all"
|
||||
br clear="all"
|
||||
|
||||
javascript:
|
||||
|
||||
|
||||
$(document).on('JAMKAZAM_READY', function(e, data) {
|
||||
var song = new JK.IndividualJamTrack(data.app);
|
||||
song.initialize();
|
||||
})
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
- provide(:page_name, 'landing_page full landing_jamtrack individual_jamtrack_band')
|
||||
|
||||
.two_by_two
|
||||
.row
|
||||
.column
|
||||
h1
|
||||
| We Have
|
||||
span.jamtrack_band_info
|
||||
|
|
||||
span.jamtrack_noun JamTracks
|
||||
span.check-it-out , Check One Out!
|
||||
p Click the play buttons below to hear the master mix and each fully isolated track. All are included in each single JamTrack.
|
||||
.previews
|
||||
.column
|
||||
h1 See What You Can Do With JamTracks
|
||||
.video-wrapper
|
||||
.video-container
|
||||
iframe src="//www.youtube.com/embed/gAJAIHMyois" frameborder="0" allowfullscreen
|
||||
br clear="all"
|
||||
.row
|
||||
.column
|
||||
h1
|
||||
| Get Your First JamTrack Free Now!
|
||||
p Click the GET A JAMTRACK FREE button below. Browse to find the one you want. Click Add to cart, and we'll apply a credit during checkout to make this first one free! We're confident you'll be back for more.
|
||||
.browse-jamtracks-wrapper
|
||||
a.white-bordered-button href="/client#/jamtrack" GET A JAMTRACK FREE!
|
||||
.column
|
||||
h1 Why Are JamTracks Different & Better?
|
||||
p
|
||||
| JamTracks are the best way to play with your favorite music.
|
||||
| Unlike traditional backing tracks, JamTracks are complete multitrack recordings,
|
||||
| with fully isolated tracks for each part. Used with the free JamKazam app/service, you can:
|
||||
ul.jamtrack-reasons
|
||||
li Solo just the individual track you want to play to hear and learn it
|
||||
li Mute just the track you want to play, and play along with the rest
|
||||
li Make audio recordings and share them via Facebook or URL
|
||||
li Make video recordings and share them via YouTube or URL
|
||||
li And even go online to play JamTracks with others in real time!
|
||||
br clear="all"
|
||||
br clear="all"
|
||||
|
||||
javascript:
|
||||
$(document).on('JAMKAZAM_READY', function(e, data) {
|
||||
var song = new JK.IndividualJamTrackBand(data.app);
|
||||
song.initialize();
|
||||
})
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
- provide(:page_name, 'landing_page full landing_product product_jamblaster')
|
||||
|
||||
.two_by_two
|
||||
.row
|
||||
.column
|
||||
h1.product-headline
|
||||
| The JamBlaster by JamKazam
|
||||
p.product-description
|
||||
| The JamBlaster is a device designed from the ground up to meet the unique requirements of real-time, online, distributed music performance. This device vastly extends the range/distance over which musicians can play together across the Internet.
|
||||
ul
|
||||
li Radically reduces audio processing latency compared to today's industry standard computers and audio interfaces.
|
||||
li Delivers plug-and-play ease of use, with no worries about hardware and software incompatibilities, driver problems, and arcane configurations.
|
||||
li Combines both a computer and an audio interface into a single elegant device.
|
||||
li Works with computers (even old crappy ones), tablets or smartphones.
|
||||
li Works with your favorite recording software applications like Garage Band, Reaper, Pro Tools, etc.
|
||||
.column
|
||||
h1 See What You Can Do With The JamBlaster
|
||||
.video-wrapper
|
||||
.video-container
|
||||
iframe src="//www.youtube.com/embed/2Zk7-04IAx4" frameborder="0" allowfullscreen
|
||||
br clear="all"
|
||||
.row
|
||||
.column
|
||||
h1
|
||||
| Want a JamBlaster? Need One?
|
||||
p If you are a registered member of the JamKazam community, and if you "know" you will buy a JamBlaster for $199 as soon as they become available, then click the button below to add yourself to our wait list. When we get enough "virtual orders", we'll reach back out to all signups to take real orders.
|
||||
|
||||
.cta-big-button
|
||||
a.white-bordered-button href="#" SIGN UP TO BUY A JAMBLASTER
|
||||
.column
|
||||
h1 Want To Know More About Latency?
|
||||
p
|
||||
| How is it possible that someone hundreds of miles away could feel like they are 20 feet away from you? Check out this video on latency to understand more:
|
||||
.linked-video-holder
|
||||
a href="https://www.youtube.com/watch?v=mB3_KMse-J4" rel="external" Watch Video About Latency - It's Pretty Fascinating
|
||||
br clear="all"
|
||||
br clear="all"
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
- provide(:page_name, 'landing_page full landing_product product_jamtracks')
|
||||
|
||||
.two_by_two
|
||||
.row
|
||||
.column
|
||||
h1.product-headline
|
||||
| JamTracks by JamKazam
|
||||
p.product-description
|
||||
| We have 100+ amazing JamTracks. Click the play buttons to hear the master mix and fully isolated track. All are included in each JamTrack.
|
||||
.previews
|
||||
.column
|
||||
h1 See What You Can With JamTracks
|
||||
.video-wrapper
|
||||
.video-container
|
||||
iframe src="//www.youtube.com/embed/2Zk7-04IAx4" frameborder="0" allowfullscreen
|
||||
br clear="all"
|
||||
.row
|
||||
.column
|
||||
h1
|
||||
| Get Your First JamTrack Free Now!
|
||||
p Click the GET A JAMTRACK FREE button below. Browse to find the one you want, click the Add to cart, and we'll apply a credit during checkout to make the first one free! We're confident you'll be back for more.
|
||||
|
||||
.cta-big-button
|
||||
a.white-bordered-button href="/client#/jamtrack" GET A JAMTRACK FREE!
|
||||
.column
|
||||
h1 Why are JamTracks Better than Backing Tracks?
|
||||
p
|
||||
| JamTracks are the best way to play with your favorite music. Unlike traditional backing tracks, JamTracks are complete multitrack recordings, with fully isolated tracks for each part. Used with the free JamKazam app/service, you can:
|
||||
ul.jamtrack-reasons
|
||||
li Solo just the individual track you want to play to hear and learn it
|
||||
li Mute just the track you want to play, and play along with the rest
|
||||
li Make audio recordings and share them via Facebook or URL
|
||||
li Make video recordings and share them via YouTube or URL
|
||||
li And even go online to play JamTracks with others in real time!
|
||||
br clear="all"
|
||||
br clear="all"
|
||||
|
||||
javascript:
|
||||
$(document).on('JAMKAZAM_READY', function (e, data) {
|
||||
var song = new JK.IndividualJamTrack(data.app);
|
||||
song.initialize();
|
||||
})
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
- provide(:page_name, 'landing_page full landing_product product_platform')
|
||||
|
||||
.two_by_two
|
||||
.row
|
||||
.column
|
||||
h1.product-headline
|
||||
| The JamKazam Platform
|
||||
p.product-description
|
||||
| JamKazam is an innovative live music platform and social network, enabling musicians to play music together in real time from different locations over the internet as if they are sitting in the same room. The core platform is free to use and delivers immense value:
|
||||
ul
|
||||
li Play music from home with your friends and bandmates without packing and transporting gear, and without needing a rehearsal space
|
||||
li Connect with new musician friends from our community of thousands of musicians to play more often, explore new styles, learn from others
|
||||
li Find musicians to join your band, or find a band to join, either virtual on JamKazam, or real world to meet and play in person
|
||||
li Schedule sessions or jump into ad hoc jams
|
||||
li Make and share recordings or session performances via Facebook or URL
|
||||
li Live broadcast sessions to family, friends, and fans
|
||||
li List your band for hire to play gigs at clubs and events
|
||||
li List yourself for hire to play studio sessions or lay down recorded tracks remotely
|
||||
.column
|
||||
h1 See What You Can Do With JamKazam
|
||||
.video-wrapper
|
||||
.video-container
|
||||
iframe src="//www.youtube.com/embed/ylYcvTY9CVo" frameborder="0" allowfullscreen
|
||||
br clear="all"
|
||||
.row
|
||||
.column
|
||||
h1
|
||||
| Sign Up for JamKazam Now, It's Free!
|
||||
p Yep, seriously. Sign up and start playing music online in real time with your friends - or make new ones from our community of thousands of musicians. It's free to play with others as much as you want.
|
||||
|
||||
.cta-big-button
|
||||
a.white-bordered-button href="/signup" SIGN UP NOW FOR YOUR FREE ACCOUNT
|
||||
.column
|
||||
h1 Does This Really Work?
|
||||
p
|
||||
| Feeling skeptical about whether this can actually work? That's natural. We'd encourage you to watch a video of endorsements and kudos from just a few of the musicians who use JamKazam.
|
||||
.linked-video-holder
|
||||
a href="https://www.youtube.com/watch?v=_7qj5RXyHCo" rel="external" Check Out Endorsements Of Real Users
|
||||
br clear="all"
|
||||
br clear="all"
|
||||
|
|
@ -85,6 +85,7 @@
|
|||
<%= render "clients/help" %>
|
||||
<%= render "clients/listenBroadcast" %>
|
||||
<%= render "clients/flash" %>
|
||||
<%= render "clients/jam_track_preview" %>
|
||||
<%= render 'dialogs/dialogs' %>
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,40 @@
|
|||
|
||||
- provide(:title, 'Jam Track Preview')
|
||||
|
||||
.content-wrapper
|
||||
h2 Jam Track Preview
|
||||
|
||||
#players
|
||||
|
||||
|
||||
javascript:
|
||||
var initialized = false;
|
||||
$(document).on('JAMKAZAM_READY', function(e, data) {
|
||||
|
||||
var rest = JK.Rest();
|
||||
|
||||
if(gon.jamTrackPlanCode) {
|
||||
rest.getJamTrack({plan_code: gon.jamTrackPlanCode})
|
||||
.done(function(jamTrack) {
|
||||
var $players = $('#players')
|
||||
|
||||
_.each(jamTrack.tracks, function(track) {
|
||||
|
||||
var $element = $('<div class="meh"></div>')
|
||||
|
||||
$players.append($element);
|
||||
|
||||
new JK.JamTrackPreview(data.app, $element, jamTrack, track, {master_shows_duration: true})
|
||||
})
|
||||
})
|
||||
.fail(function() {
|
||||
alert("couldn't fetch jam track")
|
||||
})
|
||||
|
||||
}
|
||||
else {
|
||||
alert("You need to add ?jam_track_plan_code=jamtracks-acdc-backinblack for this to work (or any jamtrack 'plancode')")
|
||||
}
|
||||
|
||||
|
||||
})
|
||||
|
|
@ -318,5 +318,7 @@ if defined?(Bundler)
|
|||
config.metronome_available = true
|
||||
config.backing_tracks_available = true
|
||||
config.one_free_jamtrack_per_user = true
|
||||
|
||||
config.nominated_jam_track = 'jamtrack-pearljam-alive'
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -30,6 +30,13 @@ SampleApp::Application.routes.draw do
|
|||
match '/landing/kick2', to: 'landings#watch_overview_kick2', via: :get, as: 'landing_kick2'
|
||||
match '/landing/kick3', to: 'landings#watch_overview_kick3', via: :get, as: 'landing_kick3'
|
||||
match '/landing/kick4', to: 'landings#watch_overview_kick4', via: :get, as: 'landing_kick4'
|
||||
match '/landing/jamtracks/:plan_code', to: 'landings#individual_jamtrack', via: :get, as: 'individual_jamtrack'
|
||||
match '/landing/jamtracks/band/:plan_code', to: 'landings#individual_jamtrack_band', via: :get, as: 'individual_jamtrack_band'
|
||||
|
||||
# product pages
|
||||
match '/products/jamblaster', to: 'landings#product_jamblaster', via: :get, as: 'product_jamblaster'
|
||||
match '/products/platform', to: 'landings#product_platform', via: :get, as: 'product_platform'
|
||||
match '/products/jamtracks', to: 'landings#product_jamtracks', via: :get, as: 'product_jamtracks'
|
||||
|
||||
# oauth
|
||||
match '/auth/:provider/callback', :to => 'sessions#oauth_callback'
|
||||
|
|
@ -94,7 +101,8 @@ SampleApp::Application.routes.draw do
|
|||
match '/launch_app', to: 'spikes#launch_app'
|
||||
match '/websocket', to: 'spikes#websocket'
|
||||
match '/test_subscription', to: 'spikes#subscription'
|
||||
match '/widgets/download_jam_track', to: 'spikes#download_jam_track'
|
||||
match '/widgets/download_jam_track', to: 'spikes #download_jam_track'
|
||||
match '/widgets/jam_track_preview', to: 'spikes#jam_track_preview'
|
||||
match '/site_validate', to: 'spikes#site_validate'
|
||||
match '/recording_source', to: 'spikes#recording_source'
|
||||
match '/musician_search_filter', to: 'spikes#musician_search_filter'
|
||||
|
|
@ -205,6 +213,8 @@ SampleApp::Application.routes.draw do
|
|||
match '/backing_tracks' => 'api_backing_tracks#index', :via => :get, :as => 'api_backing_tracks_list'
|
||||
|
||||
# Jamtracks
|
||||
match '/jamtracks/:plan_code' => 'api_jam_tracks#show', :via => :get, :as => 'api_jam_tracks_show'
|
||||
match '/jamtracks/band/:plan_code' => 'api_jam_tracks#show_with_artist_info', :via => :get, :as => 'api_jam_tracks_show_with_artist_info'
|
||||
match '/jamtracks' => 'api_jam_tracks#index', :via => :get, :as => 'api_jam_tracks_list'
|
||||
match '/jamtracks/purchased' => 'api_jam_tracks#purchased', :via => :get, :as => 'api_jam_tracks_purchased'
|
||||
match '/jamtracks/download/:id' => 'api_jam_tracks#download', :via => :get, :as => 'api_jam_tracks_download'
|
||||
|
|
|
|||
|
|
@ -24,4 +24,60 @@ namespace :jam_tracks do
|
|||
|
||||
JamTrackImporter.synchronize_all(skip_audio_upload:true)
|
||||
end
|
||||
|
||||
|
||||
task sync_master_preview_all: :environment do |task, args|
|
||||
importer = JamTrackImporter.synchronize_jamtrack_master_previews
|
||||
end
|
||||
|
||||
# syncs just one master track for a give JamTrack
|
||||
task sync_master_preview: :environment do |task, args|
|
||||
plan_code = ENV['PLAN_CODE']
|
||||
if !plan_code
|
||||
puts "PLAN_CODE must be set to something like jamtrack-acdc-backinblack"
|
||||
exit(1)
|
||||
end
|
||||
|
||||
jam_track = JamTrack.find_by_plan_code!(plan_code)
|
||||
|
||||
importer = JamTrackImporter.synchronize_jamtrack_master_preview(jam_track)
|
||||
|
||||
if importer.reason.nil? || importer.reason == "success" || importer.reason == "jam_track_exists"
|
||||
puts("#{importer.name} #{importer.reason}")
|
||||
else
|
||||
puts("#{importer.name} failed to import.")
|
||||
puts("#{importer.name} reason=#{importer.reason}")
|
||||
puts("#{importer.name} detail=#{importer.detail}")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
task sync_duration_all: :environment do |task, args|
|
||||
importer = JamTrackImporter.synchronize_durations
|
||||
end
|
||||
|
||||
# syncs just one master track for a give JamTrack
|
||||
task sync_duration: :environment do |task, args|
|
||||
plan_code = ENV['PLAN_CODE']
|
||||
if !plan_code
|
||||
puts "PLAN_CODE must be set to something like jamtrack-acdc-backinblack"
|
||||
exit(1)
|
||||
end
|
||||
|
||||
jam_track = JamTrack.find_by_plan_code!(plan_code)
|
||||
|
||||
importer = JamTrackImporter.synchronize_duration(jam_track)
|
||||
|
||||
if importer.reason.nil? || importer.reason == "success" || importer.reason == "jam_track_exists"
|
||||
puts("#{importer.name} #{importer.reason}")
|
||||
else
|
||||
puts("#{importer.name} failed to import.")
|
||||
puts("#{importer.name} reason=#{importer.reason}")
|
||||
puts("#{importer.name} detail=#{importer.detail}")
|
||||
end
|
||||
end
|
||||
|
||||
task download_masters: :environment do |task, arg|
|
||||
JamTrackImporter.download_masters
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,106 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe "Individual JamTrack Band", :js => true, :type => :feature, :capybara_feature => true do
|
||||
|
||||
subject { page }
|
||||
|
||||
before(:all) do
|
||||
ShoppingCart.delete_all
|
||||
JamTrackRight.delete_all
|
||||
JamTrack.delete_all
|
||||
JamTrackTrack.delete_all
|
||||
JamTrackLicensor.delete_all
|
||||
end
|
||||
|
||||
let(:user) { FactoryGirl.create(:user) }
|
||||
let(:jamtrack_acdc_backinblack) { @jamtrack_acdc_backinblack }
|
||||
|
||||
let(:billing_info) {
|
||||
{
|
||||
first_name: 'Seth',
|
||||
last_name: 'Call',
|
||||
address1: '10704 Buckthorn Drive',
|
||||
city: 'Austin',
|
||||
state: 'Texas',
|
||||
country: 'US',
|
||||
zip: '78759',
|
||||
number: '4111111111111111',
|
||||
month: '08',
|
||||
year: '2017',
|
||||
verification_value: '012'
|
||||
}
|
||||
}
|
||||
|
||||
def create_account(user, billing_info)
|
||||
@recurlyClient.create_account(user, billing_info)
|
||||
@created_accounts << user
|
||||
end
|
||||
|
||||
|
||||
before(:all) do
|
||||
|
||||
@recurlyClient = RecurlyClient.new
|
||||
@created_accounts = []
|
||||
|
||||
@jamtrack_acdc_backinblack = FactoryGirl.create(:jam_track, name: 'Back in Black', original_artist: 'AC/DC', sales_region: 'United States', make_track: true, plan_code: 'jamtrack-acdc-backinblack')
|
||||
|
||||
# make sure plans are there
|
||||
@recurlyClient.create_jam_track_plan(@jamtrack_acdc_backinblack) unless @recurlyClient.find_jam_track_plan(@jamtrack_acdc_backinblack)
|
||||
end
|
||||
|
||||
|
||||
after(:each) do
|
||||
@created_accounts.each do |user|
|
||||
if user.recurly_code
|
||||
begin
|
||||
@account = Recurly::Account.find(user.recurly_code)
|
||||
if @account.present?
|
||||
@account.destroy
|
||||
end
|
||||
rescue
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "AC/DC Back in Black" do
|
||||
|
||||
it "logged out" do
|
||||
visit "/landing/jamtracks/band/acdc-backinblack"
|
||||
|
||||
find('h1', text: "We Have 1 #{@jamtrack_acdc_backinblack.original_artist} JamTrack, Check It Out!")
|
||||
jamtrack_acdc_backinblack.jam_track_tracks.each do |track|
|
||||
if track.master?
|
||||
find('.jam-track-preview-holder[data-id="' + track.id + '"] img.instrument-icon[data-instrument-id="other"]')
|
||||
find('.jam-track-preview-holder[data-id="' + track.id + '"] .instrument-name', text:'Master Mix')
|
||||
else
|
||||
find('.jam-track-preview-holder[data-id="' + track.id + '"] img.instrument-icon[data-instrument-id="' + track.instrument.id + '"]')
|
||||
find('.jam-track-preview-holder[data-id="' + track.id + '"] .instrument-name', text:track.instrument.description)
|
||||
end
|
||||
end
|
||||
find('a.white-bordered-button')['href'].should eq("/client?artist=#{jamtrack_acdc_backinblack.original_artist}#/jamtrack")
|
||||
|
||||
find('a.white-bordered-button').trigger(:click)
|
||||
find('h1', text: 'jamtracks')
|
||||
end
|
||||
|
||||
it "logged in" do
|
||||
fast_signin(user, "/landing/jamtracks/band/acdc-backinblack")
|
||||
|
||||
find('h1', text: "We Have 1 #{@jamtrack_acdc_backinblack.original_artist} JamTrack, Check It Out!")
|
||||
jamtrack_acdc_backinblack.jam_track_tracks.each do |track|
|
||||
if track.master?
|
||||
find('.jam-track-preview-holder[data-id="' + track.id + '"] img.instrument-icon[data-instrument-id="other"]')
|
||||
find('.jam-track-preview-holder[data-id="' + track.id + '"] .instrument-name', text:'Master Mix')
|
||||
else
|
||||
find('.jam-track-preview-holder[data-id="' + track.id + '"] img.instrument-icon[data-instrument-id="' + track.instrument.id + '"]')
|
||||
find('.jam-track-preview-holder[data-id="' + track.id + '"] .instrument-name', text:track.instrument.description)
|
||||
end
|
||||
end
|
||||
find('a.white-bordered-button')['href'].should eq("/client?artist=#{jamtrack_acdc_backinblack.original_artist}#/jamtrack")
|
||||
|
||||
find('a.white-bordered-button').trigger(:click)
|
||||
find('h1', text: 'jamtracks')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,125 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe "Individual JamTrack", :js => true, :type => :feature, :capybara_feature => true do
|
||||
|
||||
subject { page }
|
||||
|
||||
before(:all) do
|
||||
ShoppingCart.delete_all
|
||||
JamTrackRight.delete_all
|
||||
JamTrack.delete_all
|
||||
JamTrackTrack.delete_all
|
||||
JamTrackLicensor.delete_all
|
||||
end
|
||||
|
||||
let(:user) { FactoryGirl.create(:user) }
|
||||
let(:jamtrack_acdc_backinblack) { @jamtrack_acdc_backinblack }
|
||||
|
||||
let(:billing_info) {
|
||||
{
|
||||
first_name: 'Seth',
|
||||
last_name: 'Call',
|
||||
address1: '10704 Buckthorn Drive',
|
||||
city: 'Austin',
|
||||
state: 'Texas',
|
||||
country: 'US',
|
||||
zip: '78759',
|
||||
number: '4111111111111111',
|
||||
month: '08',
|
||||
year: '2017',
|
||||
verification_value: '012'
|
||||
}
|
||||
}
|
||||
|
||||
def create_account(user, billing_info)
|
||||
@recurlyClient.create_account(user, billing_info)
|
||||
@created_accounts << user
|
||||
end
|
||||
|
||||
|
||||
before(:all) do
|
||||
|
||||
@recurlyClient = RecurlyClient.new
|
||||
@created_accounts = []
|
||||
|
||||
@jamtrack_acdc_backinblack = FactoryGirl.create(:jam_track, name: 'Back in Black', original_artist: 'AC/DC', sales_region: 'United States', make_track: true, plan_code: 'jamtrack-acdc-backinblack')
|
||||
|
||||
# make sure plans are there
|
||||
@recurlyClient.create_jam_track_plan(@jamtrack_acdc_backinblack) unless @recurlyClient.find_jam_track_plan(@jamtrack_acdc_backinblack)
|
||||
end
|
||||
|
||||
|
||||
after(:each) do
|
||||
@created_accounts.each do |user|
|
||||
if user.recurly_code
|
||||
begin
|
||||
@account = Recurly::Account.find(user.recurly_code)
|
||||
if @account.present?
|
||||
@account.destroy
|
||||
end
|
||||
rescue
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "AC/DC Back in Black" do
|
||||
|
||||
it "logged out" do
|
||||
visit "/landing/jamtracks/acdc-backinblack"
|
||||
|
||||
find('h1', text: 'Check Out Our Back in Black JamTrack')
|
||||
jamtrack_acdc_backinblack.jam_track_tracks.each do |track|
|
||||
if track.master?
|
||||
find('.jam-track-preview-holder[data-id="' + track.id + '"] img.instrument-icon[data-instrument-id="other"]')
|
||||
find('.jam-track-preview-holder[data-id="' + track.id + '"] .instrument-name', text:'Master Mix')
|
||||
else
|
||||
find('.jam-track-preview-holder[data-id="' + track.id + '"] img.instrument-icon[data-instrument-id="' + track.instrument.id + '"]')
|
||||
find('.jam-track-preview-holder[data-id="' + track.id + '"] .instrument-name', text:track.instrument.description)
|
||||
end
|
||||
end
|
||||
find('a.white-bordered-button')['href'].should eq("/client?artist=#{jamtrack_acdc_backinblack.original_artist}#/jamtrack")
|
||||
|
||||
find('a.white-bordered-button').trigger(:click)
|
||||
find('h1', text: 'jamtracks')
|
||||
end
|
||||
|
||||
it "logged in" do
|
||||
fast_signin(user, "/landing/jamtracks/acdc-backinblack")
|
||||
|
||||
find('h1', text: 'Check Out Our Back in Black JamTrack')
|
||||
jamtrack_acdc_backinblack.jam_track_tracks.each do |track|
|
||||
if track.master?
|
||||
find('.jam-track-preview-holder[data-id="' + track.id + '"] img.instrument-icon[data-instrument-id="other"]')
|
||||
find('.jam-track-preview-holder[data-id="' + track.id + '"] .instrument-name', text:'Master Mix')
|
||||
else
|
||||
find('.jam-track-preview-holder[data-id="' + track.id + '"] img.instrument-icon[data-instrument-id="' + track.instrument.id + '"]')
|
||||
find('.jam-track-preview-holder[data-id="' + track.id + '"] .instrument-name', text:track.instrument.description)
|
||||
end
|
||||
end
|
||||
find('a.white-bordered-button')['href'].should eq("/client?artist=#{jamtrack_acdc_backinblack.original_artist}#/jamtrack")
|
||||
|
||||
find('a.white-bordered-button').trigger(:click)
|
||||
find('h1', text: 'jamtracks')
|
||||
end
|
||||
|
||||
it "generic version" do
|
||||
visit "/landing/jamtracks/acdc-backinblack?generic=true"
|
||||
|
||||
find('h1', text: 'We Have 100+ Amazing JamTracks, Check One Out!')
|
||||
jamtrack_acdc_backinblack.jam_track_tracks.each do |track|
|
||||
if track.master?
|
||||
find('.jam-track-preview-holder[data-id="' + track.id + '"] img.instrument-icon[data-instrument-id="other"]')
|
||||
find('.jam-track-preview-holder[data-id="' + track.id + '"] .instrument-name', text:'Master Mix')
|
||||
else
|
||||
find('.jam-track-preview-holder[data-id="' + track.id + '"] img.instrument-icon[data-instrument-id="' + track.instrument.id + '"]')
|
||||
find('.jam-track-preview-holder[data-id="' + track.id + '"] .instrument-name', text:track.instrument.description)
|
||||
end
|
||||
end
|
||||
find('a.white-bordered-button')['href'].should eq("/client#/jamtrack")
|
||||
|
||||
find('a.white-bordered-button').trigger(:click)
|
||||
find('h1', text: 'jamtracks')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,122 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe "Product Pages", :js => true, :type => :feature, :capybara_feature => true do
|
||||
|
||||
subject { page }
|
||||
|
||||
before(:all) do
|
||||
ShoppingCart.delete_all
|
||||
JamTrackRight.delete_all
|
||||
JamTrack.delete_all
|
||||
JamTrackTrack.delete_all
|
||||
JamTrackLicensor.delete_all
|
||||
end
|
||||
|
||||
let(:user) { FactoryGirl.create(:user) }
|
||||
let(:jamtrack_acdc_backinblack) { @jamtrack_acdc_backinblack }
|
||||
|
||||
let(:billing_info) {
|
||||
{
|
||||
first_name: 'Seth',
|
||||
last_name: 'Call',
|
||||
address1: '10704 Buckthorn Drive',
|
||||
city: 'Austin',
|
||||
state: 'Texas',
|
||||
country: 'US',
|
||||
zip: '78759',
|
||||
number: '4111111111111111',
|
||||
month: '08',
|
||||
year: '2017',
|
||||
verification_value: '012'
|
||||
}
|
||||
}
|
||||
|
||||
def create_account(user, billing_info)
|
||||
@recurlyClient.create_account(user, billing_info)
|
||||
@created_accounts << user
|
||||
end
|
||||
|
||||
|
||||
before(:all) do
|
||||
|
||||
@recurlyClient = RecurlyClient.new
|
||||
@created_accounts = []
|
||||
|
||||
@jamtrack_acdc_backinblack = FactoryGirl.create(:jam_track, name: 'Back in Black', original_artist: 'AC/DC', sales_region: 'United States', make_track: true, plan_code: 'jamtrack-acdc-backinblack')
|
||||
|
||||
# make sure plans are there
|
||||
@recurlyClient.create_jam_track_plan(@jamtrack_acdc_backinblack) unless @recurlyClient.find_jam_track_plan(@jamtrack_acdc_backinblack)
|
||||
end
|
||||
|
||||
|
||||
after(:each) do
|
||||
@created_accounts.each do |user|
|
||||
if user.recurly_code
|
||||
begin
|
||||
@account = Recurly::Account.find(user.recurly_code)
|
||||
if @account.present?
|
||||
@account.destroy
|
||||
end
|
||||
rescue
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "JamBlaster" do
|
||||
it "logged out" do
|
||||
visit "/products/jamblaster"
|
||||
|
||||
find('h1', text: 'The JamBlaster by JamKazam')
|
||||
find('a.white-bordered-button')['href'].should eq("#") # nowhere to go yet
|
||||
end
|
||||
|
||||
it "logged in" do
|
||||
fast_signin(user, "/products/jamblaster")
|
||||
|
||||
find('h1', text: 'The JamBlaster by JamKazam')
|
||||
find('a.white-bordered-button')['href'].should eq("#") # nowhere to go yet
|
||||
end
|
||||
end
|
||||
|
||||
describe "Platform" do
|
||||
it "logged out" do
|
||||
visit "/products/platform"
|
||||
|
||||
find('h1', text: 'The JamKazam Platform')
|
||||
find('a.white-bordered-button').trigger(:click)
|
||||
|
||||
find('h2', text: 'Create your free JamKazam account')
|
||||
end
|
||||
|
||||
it "logged in" do
|
||||
fast_signin(user, "/products/platform")
|
||||
|
||||
find('h1', text: 'The JamKazam Platform')
|
||||
find('a.white-bordered-button').trigger(:click)
|
||||
|
||||
# clicking /signup just redirects you to the client
|
||||
find('h2', text: 'create session')
|
||||
end
|
||||
end
|
||||
|
||||
describe "JamTracks" do
|
||||
it "logged out" do
|
||||
visit "/products/jamtracks"
|
||||
|
||||
find('h1', text: 'JamTracks by JamKazam')
|
||||
find('a.white-bordered-button').trigger(:click)
|
||||
|
||||
find('h1', text: 'jamtracks')
|
||||
end
|
||||
|
||||
it "logged in" do
|
||||
fast_signin(user, "/products/jamtracks")
|
||||
|
||||
find('h1', text: 'JamTracks by JamKazam')
|
||||
find('a.white-bordered-button').trigger(:click)
|
||||
|
||||
find('h1', text: 'jamtracks')
|
||||
end
|
||||
end
|
||||
end
|
||||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue