merging develop

This commit is contained in:
Jonathan Kolyer 2015-10-05 14:06:39 +00:00
commit 0c25d0e40b
125 changed files with 2339 additions and 421 deletions

16
admin/bin/_guard-core Executable file
View File

@ -0,0 +1,16 @@
#!/usr/bin/env ruby
#
# This file was generated by Bundler.
#
# The application '_guard-core' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'pathname'
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)
require 'rubygems'
require 'bundler/setup'
load Gem.bin_path('guard', '_guard-core')

16
admin/bin/autospec Executable file
View File

@ -0,0 +1,16 @@
#!/usr/bin/env ruby
#
# This file was generated by Bundler.
#
# The application 'autospec' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'pathname'
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)
require 'rubygems'
require 'bundler/setup'
load Gem.bin_path('rspec-core', 'autospec')

16
admin/bin/aws-rb Executable file
View File

@ -0,0 +1,16 @@
#!/usr/bin/env ruby
#
# This file was generated by Bundler.
#
# The application 'aws-rb' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'pathname'
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)
require 'rubygems'
require 'bundler/setup'
load Gem.bin_path('aws-sdk-v1', 'aws-rb')

16
admin/bin/bourbon Executable file
View File

@ -0,0 +1,16 @@
#!/usr/bin/env ruby
#
# This file was generated by Bundler.
#
# The application 'bourbon' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'pathname'
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)
require 'rubygems'
require 'bundler/setup'
load Gem.bin_path('bourbon', 'bourbon')

16
admin/bin/bundler Executable file
View File

@ -0,0 +1,16 @@
#!/usr/bin/env ruby
#
# This file was generated by Bundler.
#
# The application 'bundler' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'pathname'
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)
require 'rubygems'
require 'bundler/setup'
load Gem.bin_path('bundler', 'bundler')

16
admin/bin/coderay Executable file
View File

@ -0,0 +1,16 @@
#!/usr/bin/env ruby
#
# This file was generated by Bundler.
#
# The application 'coderay' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'pathname'
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)
require 'rubygems'
require 'bundler/setup'
load Gem.bin_path('coderay', 'coderay')

16
admin/bin/erubis Executable file
View File

@ -0,0 +1,16 @@
#!/usr/bin/env ruby
#
# This file was generated by Bundler.
#
# The application 'erubis' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'pathname'
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)
require 'rubygems'
require 'bundler/setup'
load Gem.bin_path('erubis', 'erubis')

16
admin/bin/fission Executable file
View File

@ -0,0 +1,16 @@
#!/usr/bin/env ruby
#
# This file was generated by Bundler.
#
# The application 'fission' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'pathname'
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)
require 'rubygems'
require 'bundler/setup'
load Gem.bin_path('fission', 'fission')

16
admin/bin/fog Executable file
View File

@ -0,0 +1,16 @@
#!/usr/bin/env ruby
#
# This file was generated by Bundler.
#
# The application 'fog' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'pathname'
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)
require 'rubygems'
require 'bundler/setup'
load Gem.bin_path('fog', 'fog')

16
admin/bin/fpm Executable file
View File

@ -0,0 +1,16 @@
#!/usr/bin/env ruby
#
# This file was generated by Bundler.
#
# The application 'fpm' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'pathname'
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)
require 'rubygems'
require 'bundler/setup'
load Gem.bin_path('fpm', 'fpm')

16
admin/bin/guard Executable file
View File

@ -0,0 +1,16 @@
#!/usr/bin/env ruby
#
# This file was generated by Bundler.
#
# The application 'guard' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'pathname'
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)
require 'rubygems'
require 'bundler/setup'
load Gem.bin_path('guard', 'guard')

16
admin/bin/haml Executable file
View File

@ -0,0 +1,16 @@
#!/usr/bin/env ruby
#
# This file was generated by Bundler.
#
# The application 'haml' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'pathname'
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)
require 'rubygems'
require 'bundler/setup'
load Gem.bin_path('haml', 'haml')

16
admin/bin/htmldiff Executable file
View File

@ -0,0 +1,16 @@
#!/usr/bin/env ruby
#
# This file was generated by Bundler.
#
# The application 'htmldiff' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'pathname'
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)
require 'rubygems'
require 'bundler/setup'
load Gem.bin_path('diff-lcs', 'htmldiff')

16
admin/bin/jam_db Executable file
View File

@ -0,0 +1,16 @@
#!/usr/bin/env ruby
#
# This file was generated by Bundler.
#
# The application 'jam_db' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'pathname'
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)
require 'rubygems'
require 'bundler/setup'
load Gem.bin_path('jam_db', 'jam_db')

16
admin/bin/jasmine Executable file
View File

@ -0,0 +1,16 @@
#!/usr/bin/env ruby
#
# This file was generated by Bundler.
#
# The application 'jasmine' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'pathname'
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)
require 'rubygems'
require 'bundler/setup'
load Gem.bin_path('jasmine', 'jasmine')

16
admin/bin/launchy Executable file
View File

@ -0,0 +1,16 @@
#!/usr/bin/env ruby
#
# This file was generated by Bundler.
#
# The application 'launchy' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'pathname'
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)
require 'rubygems'
require 'bundler/setup'
load Gem.bin_path('launchy', 'launchy')

16
admin/bin/ldiff Executable file
View File

@ -0,0 +1,16 @@
#!/usr/bin/env ruby
#
# This file was generated by Bundler.
#
# The application 'ldiff' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'pathname'
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)
require 'rubygems'
require 'bundler/setup'
load Gem.bin_path('diff-lcs', 'ldiff')

16
admin/bin/listen Executable file
View File

@ -0,0 +1,16 @@
#!/usr/bin/env ruby
#
# This file was generated by Bundler.
#
# The application 'listen' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'pathname'
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)
require 'rubygems'
require 'bundler/setup'
load Gem.bin_path('listen', 'listen')

16
admin/bin/mix_cron.rb Executable file
View File

@ -0,0 +1,16 @@
#!/usr/bin/env ruby
#
# This file was generated by Bundler.
#
# The application 'mix_cron.rb' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'pathname'
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)
require 'rubygems'
require 'bundler/setup'
load Gem.bin_path('jam_ruby', 'mix_cron.rb')

16
admin/bin/nokogiri Executable file
View File

@ -0,0 +1,16 @@
#!/usr/bin/env ruby
#
# This file was generated by Bundler.
#
# The application 'nokogiri' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'pathname'
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)
require 'rubygems'
require 'bundler/setup'
load Gem.bin_path('nokogiri', 'nokogiri')

16
admin/bin/pg_migrate Executable file
View File

@ -0,0 +1,16 @@
#!/usr/bin/env ruby
#
# This file was generated by Bundler.
#
# The application 'pg_migrate' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'pathname'
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)
require 'rubygems'
require 'bundler/setup'
load Gem.bin_path('pg_migrate', 'pg_migrate')

16
admin/bin/pry Executable file
View File

@ -0,0 +1,16 @@
#!/usr/bin/env ruby
#
# This file was generated by Bundler.
#
# The application 'pry' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'pathname'
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)
require 'rubygems'
require 'bundler/setup'
load Gem.bin_path('pry', 'pry')

16
admin/bin/pry-remote Executable file
View File

@ -0,0 +1,16 @@
#!/usr/bin/env ruby
#
# This file was generated by Bundler.
#
# The application 'pry-remote' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'pathname'
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)
require 'rubygems'
require 'bundler/setup'
load Gem.bin_path('pry-remote', 'pry-remote')

16
admin/bin/puma Executable file
View File

@ -0,0 +1,16 @@
#!/usr/bin/env ruby
#
# This file was generated by Bundler.
#
# The application 'puma' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'pathname'
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)
require 'rubygems'
require 'bundler/setup'
load Gem.bin_path('puma', 'puma')

16
admin/bin/pumactl Executable file
View File

@ -0,0 +1,16 @@
#!/usr/bin/env ruby
#
# This file was generated by Bundler.
#
# The application 'pumactl' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'pathname'
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)
require 'rubygems'
require 'bundler/setup'
load Gem.bin_path('puma', 'pumactl')

16
admin/bin/rackup Executable file
View File

@ -0,0 +1,16 @@
#!/usr/bin/env ruby
#
# This file was generated by Bundler.
#
# The application 'rackup' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'pathname'
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)
require 'rubygems'
require 'bundler/setup'
load Gem.bin_path('rack', 'rackup')

16
admin/bin/rails Executable file
View File

@ -0,0 +1,16 @@
#!/usr/bin/env ruby
#
# This file was generated by Bundler.
#
# The application 'rails' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'pathname'
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)
require 'rubygems'
require 'bundler/setup'
load Gem.bin_path('railties', 'rails')

16
admin/bin/rake Executable file
View File

@ -0,0 +1,16 @@
#!/usr/bin/env ruby
#
# This file was generated by Bundler.
#
# The application 'rake' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'pathname'
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)
require 'rubygems'
require 'bundler/setup'
load Gem.bin_path('rake', 'rake')

16
admin/bin/rdoc Executable file
View File

@ -0,0 +1,16 @@
#!/usr/bin/env ruby
#
# This file was generated by Bundler.
#
# The application 'rdoc' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'pathname'
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)
require 'rubygems'
require 'bundler/setup'
load Gem.bin_path('rdoc', 'rdoc')

16
admin/bin/recurly Executable file
View File

@ -0,0 +1,16 @@
#!/usr/bin/env ruby
#
# This file was generated by Bundler.
#
# The application 'recurly' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'pathname'
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)
require 'rubygems'
require 'bundler/setup'
load Gem.bin_path('recurly', 'recurly')

16
admin/bin/resque Executable file
View File

@ -0,0 +1,16 @@
#!/usr/bin/env ruby
#
# This file was generated by Bundler.
#
# The application 'resque' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'pathname'
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)
require 'rubygems'
require 'bundler/setup'
load Gem.bin_path('resque', 'resque')

16
admin/bin/resque-scheduler Executable file
View File

@ -0,0 +1,16 @@
#!/usr/bin/env ruby
#
# This file was generated by Bundler.
#
# The application 'resque-scheduler' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'pathname'
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)
require 'rubygems'
require 'bundler/setup'
load Gem.bin_path('resque-scheduler', 'resque-scheduler')

16
admin/bin/resque-web Executable file
View File

@ -0,0 +1,16 @@
#!/usr/bin/env ruby
#
# This file was generated by Bundler.
#
# The application 'resque-web' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'pathname'
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)
require 'rubygems'
require 'bundler/setup'
load Gem.bin_path('resque', 'resque-web')

16
admin/bin/restclient Executable file
View File

@ -0,0 +1,16 @@
#!/usr/bin/env ruby
#
# This file was generated by Bundler.
#
# The application 'restclient' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'pathname'
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)
require 'rubygems'
require 'bundler/setup'
load Gem.bin_path('rest-client', 'restclient')

16
admin/bin/ri Executable file
View File

@ -0,0 +1,16 @@
#!/usr/bin/env ruby
#
# This file was generated by Bundler.
#
# The application 'ri' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'pathname'
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)
require 'rubygems'
require 'bundler/setup'
load Gem.bin_path('rdoc', 'ri')

16
admin/bin/rspec Executable file
View File

@ -0,0 +1,16 @@
#!/usr/bin/env ruby
#
# This file was generated by Bundler.
#
# The application 'rspec' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'pathname'
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)
require 'rubygems'
require 'bundler/setup'
load Gem.bin_path('rspec-core', 'rspec')

16
admin/bin/ruby-protoc Executable file
View File

@ -0,0 +1,16 @@
#!/usr/bin/env ruby
#
# This file was generated by Bundler.
#
# The application 'ruby-protoc' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'pathname'
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)
require 'rubygems'
require 'bundler/setup'
load Gem.bin_path('ruby-protocol-buffers', 'ruby-protoc')

16
admin/bin/rubygems-cabin-test Executable file
View File

@ -0,0 +1,16 @@
#!/usr/bin/env ruby
#
# This file was generated by Bundler.
#
# The application 'rubygems-cabin-test' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'pathname'
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)
require 'rubygems'
require 'bundler/setup'
load Gem.bin_path('cabin', 'rubygems-cabin-test')

16
admin/bin/sass Executable file
View File

@ -0,0 +1,16 @@
#!/usr/bin/env ruby
#
# This file was generated by Bundler.
#
# The application 'sass' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'pathname'
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)
require 'rubygems'
require 'bundler/setup'
load Gem.bin_path('sass', 'sass')

16
admin/bin/sass-convert Executable file
View File

@ -0,0 +1,16 @@
#!/usr/bin/env ruby
#
# This file was generated by Bundler.
#
# The application 'sass-convert' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'pathname'
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)
require 'rubygems'
require 'bundler/setup'
load Gem.bin_path('sass', 'sass-convert')

16
admin/bin/scss Executable file
View File

@ -0,0 +1,16 @@
#!/usr/bin/env ruby
#
# This file was generated by Bundler.
#
# The application 'scss' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'pathname'
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)
require 'rubygems'
require 'bundler/setup'
load Gem.bin_path('sass', 'scss')

16
admin/bin/slimrb Executable file
View File

@ -0,0 +1,16 @@
#!/usr/bin/env ruby
#
# This file was generated by Bundler.
#
# The application 'slimrb' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'pathname'
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)
require 'rubygems'
require 'bundler/setup'
load Gem.bin_path('slim', 'slimrb')

16
admin/bin/sprockets Executable file
View File

@ -0,0 +1,16 @@
#!/usr/bin/env ruby
#
# This file was generated by Bundler.
#
# The application 'sprockets' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'pathname'
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)
require 'rubygems'
require 'bundler/setup'
load Gem.bin_path('sprockets', 'sprockets')

16
admin/bin/thor Executable file
View File

@ -0,0 +1,16 @@
#!/usr/bin/env ruby
#
# This file was generated by Bundler.
#
# The application 'thor' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'pathname'
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)
require 'rubygems'
require 'bundler/setup'
load Gem.bin_path('thor', 'thor')

16
admin/bin/tilt Executable file
View File

@ -0,0 +1,16 @@
#!/usr/bin/env ruby
#
# This file was generated by Bundler.
#
# The application 'tilt' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'pathname'
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)
require 'rubygems'
require 'bundler/setup'
load Gem.bin_path('tilt', 'tilt')

16
admin/bin/tt Executable file
View File

@ -0,0 +1,16 @@
#!/usr/bin/env ruby
#
# This file was generated by Bundler.
#
# The application 'tt' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'pathname'
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)
require 'rubygems'
require 'bundler/setup'
load Gem.bin_path('treetop', 'tt')

16
admin/bin/unicorn Executable file
View File

@ -0,0 +1,16 @@
#!/usr/bin/env ruby
#
# This file was generated by Bundler.
#
# The application 'unicorn' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'pathname'
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)
require 'rubygems'
require 'bundler/setup'
load Gem.bin_path('unicorn', 'unicorn')

16
admin/bin/unicorn_rails Executable file
View File

@ -0,0 +1,16 @@
#!/usr/bin/env ruby
#
# This file was generated by Bundler.
#
# The application 'unicorn_rails' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'pathname'
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)
require 'rubygems'
require 'bundler/setup'
load Gem.bin_path('unicorn', 'unicorn_rails')

View File

@ -304,4 +304,6 @@ jam_track_searchability.sql
harry_fox_agency.sql
jam_track_slug.sql
mixdown.sql
aac_master.sql
video_recording.sql
jam_track_lang_idx.sql

3
db/up/aac_master.sql Normal file
View File

@ -0,0 +1,3 @@
ALTER TABLE jam_track_tracks ADD COLUMN preview_aac_url VARCHAR;
ALTER TABLE jam_track_tracks ADD COLUMN preview_aac_md5 VARCHAR;
ALTER TABLE jam_track_tracks ADD COLUMN preview_aac_length bigint;

6
db/up/crash_dumps_2.sql Normal file
View File

@ -0,0 +1,6 @@
ALTER TABLE crash_dumps ADD COLUMN email VARCHAR(255);
ALTER TABLE crash_dumps ADD COLUMN description VARCHAR(10000);
ALTER TABLE crash_dumps ADD COLUMN os VARCHAR(100);
ALTER TABLE crash_dumps ADD COLUMN os_version VARCHAR(100);
ALTER TABLE crash_dumps DROP CONSTRAINT crash_dumps_user_id_fkey;

View File

@ -49,4 +49,13 @@ ALTER TABLE notifications ADD COLUMN jam_track_mixdown_package_id VARCHAR(64) RE
ALTER TABLE jam_track_mixdown_packages ADD COLUMN last_errored_at TIMESTAMP;
ALTER TABLE jam_track_mixdown_packages ADD COLUMN queued BOOLEAN DEFAULT FALSE;
ALTER TABLE jam_track_rights ADD COLUMN queued BOOLEAN DEFAULT FALSE;
ALTER TABLE jam_track_mixdown_packages ADD COLUMN speed_pitched BOOLEAN DEFAULT FALSE;
ALTER TABLE jam_track_rights ADD COLUMN queued BOOLEAN DEFAULT FALSE;
CREATE INDEX jam_track_rights_queued ON jam_track_rights(queued);
CREATE INDEX jam_track_rights_signing_queued ON jam_track_rights(signing_queued_at);
CREATE INDEX jam_track_rights_updated ON jam_track_rights(updated_at);
CREATE INDEX jam_track_mixdown_packages_queued ON jam_track_mixdown_packages(queued);
CREATE INDEX jam_track_mixdown_packages_signing_queued ON jam_track_mixdown_packages(signing_queued_at);
CREATE INDEX jam_track_mixdown_packages_updated ON jam_track_mixdown_packages(updated_at);

View File

@ -0,0 +1 @@
ALTER TABLE recordings ADD video BOOLEAN NOT NULL DEFAULT FALSE;

View File

@ -34,6 +34,70 @@ module JamRuby
end
def synchronize_preview_dev(jam_track)
jam_track.jam_track_tracks.each do |track|
next if track.track_type != 'Master'
most_recent_aac = nil
most_recent_ogg = nil
most_recent_mp3 = nil
public_jamkazam_s3_manager.list_files(track.preview_directory).each do |s3_preview_item|
s3_object = public_jamkazam_s3_manager.object(s3_preview_item)
if s3_preview_item.end_with?('.aac')
if most_recent_aac
if s3_object.last_modified > most_recent_aac.last_modified
most_recent_aac = s3_object
end
else
most_recent_aac = s3_object
end
end
if s3_preview_item.end_with?('.mp3')
if most_recent_mp3
if s3_object.last_modified > most_recent_mp3.last_modified
most_recent_mp3 = s3_object
end
else
most_recent_mp3 = s3_object
end
end
if s3_preview_item.end_with?('.ogg')
if most_recent_ogg
if s3_object.last_modified > most_recent_ogg.last_modified
most_recent_ogg = s3_object
end
else
most_recent_ogg = s3_object
end
end
end
if most_recent_aac
track['preview_aac_md5'] = 'md5'
track['preview_aac_url'] = most_recent_aac.key
track['preview_aac_length'] = most_recent_aac.content_length
end
if most_recent_mp3
track['preview_mp3_md5'] = 'md5'
track['preview_mp3_url'] = most_recent_mp3.key
track['preview_mp3_length'] = most_recent_mp3.content_length
end
if most_recent_ogg
track['preview_md5'] = 'md5'
track['preview_url'] = most_recent_ogg.key
track['preview_length'] = most_recent_ogg.content_length
end
track.save
end
end
# this method was created due to Tency-sourced data having no master track
# it goes through all audio tracks, and creates a master mix from it. (mix + normalize)
def create_master(metadata, metalocation)
@ -116,7 +180,6 @@ module JamRuby
end
temp_file = File.join(tmp_dir, "temp.wav")
output_filename = JamTrackImporter.remove_s3_special_chars("#{self.name} Master Mix.wav")
output_file = File.join(tmp_dir, output_filename)
@ -149,7 +212,7 @@ module JamRuby
# now we need to upload the output back up
s3_target = audio_path + '/' + output_filename
@@log.debug("uploading #{output_file} to #{s3_target}")
JamTrackImporter.song_storage_manager.upload(s3_target, output_file )
JamTrackImporter.song_storage_manager.upload(s3_target, output_file)
finish('success', nil)
end
@ -195,7 +258,7 @@ module JamRuby
meta[:licensor] = vendor
File.open(meta_yml, 'w') {|f| f.write meta.to_yaml }
File.open(meta_yml, 'w') { |f| f.write meta.to_yaml }
jamkazam_s3_manager.upload(metalocation, meta_yml)
end
@ -338,7 +401,7 @@ module JamRuby
genres << Genre.find('asian')
else
found = Genre.find_by_id(genre)
genres << found if found
genres << found if found
end
end
@ -1166,7 +1229,7 @@ module JamRuby
total_time = `#{total_time_command}`.to_f
result_code = -20
stripped_time = total_time # default to the case where we just start the preview at the beginning
stripped_time = total_time # default to the case where we just start the preview at the beginning
burp_gaps.each do |gap|
command_strip_lead_silence = "sox \"#{ogg_44100}\" \"#{out_wav}\" silence 1 #{gap} 1%"
@ -1218,6 +1281,53 @@ module JamRuby
end
def synchronize_aac_preview(track, tmp_dir, ogg_44100, ogg_digest)
begin
aac_44100 = File.join(tmp_dir, 'output-preview-44100.aac')
convert_aac_cmd = "#{APP_CONFIG.ffmpeg_path} -i \"#{ogg_44100}\" -c:a libfdk_aac -b:a 192k \"#{aac_44100}\""
@@log.debug("converting to aac using: " + convert_aac_cmd)
convert_output = `#{convert_aac_cmd}`
aac_digest = ::Digest::MD5.file(aac_44100)
track["preview_aac_md5"] = aac_md5 = aac_digest.hexdigest
# upload 44100 aac to public location
@@log.debug("uploading aac preview to #{track.preview_filename('aac')}")
public_jamkazam_s3_manager.upload(track.preview_filename(aac_digest.hexdigest, 'aac'), aac_44100, content_type: 'audio/aac', content_md5: aac_digest.base64digest)
track.skip_uploader = true
original_aac_preview_url = track["preview_aac_url"]
# and finally update the JamTrackTrack with the new info
track["preview_aac_url"] = track.preview_filename(aac_md5, 'aac')
track["preview_aac_length"] = File.new(aac_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_aac_preview_url) if original_aac_preview_url && original_aac_preview_url != track["preview_aac_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 synchronize_master_preview(track, tmp_dir, ogg_44100, ogg_digest)
begin
@ -1229,20 +1339,33 @@ module JamRuby
mp3_digest = ::Digest::MD5.file(mp3_44100)
aac_44100 = File.join(tmp_dir, 'output-preview-44100.aac')
convert_aac_cmd = "#{APP_CONFIG.ffmpeg_path} -i \"#{ogg_44100}\" -c:a libfdk_aac -b:a 192k \"#{aac_44100}\""
@@log.debug("converting to aac using: " + convert_aac_cmd)
convert_output = `#{convert_aac_cmd}`
aac_digest = ::Digest::MD5.file(aac_44100)
track["preview_md5"] = ogg_md5 = ogg_digest.hexdigest
track["preview_mp3_md5"] = mp3_md5 = mp3_digest.hexdigest
track["preview_aac_md5"] = aac_md5 = aac_digest.hexdigest
# upload 44100 ogg and mp3 to public location as well
# upload 44100 ogg, mp3, aac 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)
@@log.debug("uploading aac preview to #{track.preview_filename('aac')}")
public_jamkazam_s3_manager.upload(track.preview_filename(aac_digest.hexdigest, 'aac'), aac_44100, content_type: 'audio/aac', content_md5: aac_digest.base64digest)
track.skip_uploader = true
original_ogg_preview_url = track["preview_url"]
original_mp3_preview_url = track["preview_mp3_url"]
original_aac_preview_url = track["preview_aac_url"]
# and finally update the JamTrackTrack with the new info
track["preview_url"] = track.preview_filename(ogg_md5, 'ogg')
@ -1250,6 +1373,8 @@ module JamRuby
# 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_aac_url"] = track.preview_filename(aac_md5, 'mp3')
track["preview_aac_length"] = File.new(aac_44100).size
track["preview_start_time"] = 0
if !track.save
@ -1261,6 +1386,7 @@ module JamRuby
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"]
public_jamkazam_s3_manager.delete(original_aac_preview_url) if original_aac_preview_url && original_aac_preview_url != track["preview_aac_url"]
rescue
puts "UNABLE TO CLEANUP OLD PREVIEW URL"
end
@ -1499,13 +1625,13 @@ module JamRuby
CSV.open("only_in_s3.csv", "wb") do |csv|
only_in_s3.each do |song_id|
csv << [ song_id, in_s3[song_id][:artist], in_s3[song_id][:song] ]
csv << [song_id, in_s3[song_id][:artist], in_s3[song_id][:song]]
end
end
CSV.open("only_in_2k_selection.csv", "wb") do |csv|
only_in_mapping.each do |song_id|
csv << [ song_id, in_mapping[song_id][:artist], in_mapping[song_id][:song] ]
csv << [song_id, in_mapping[song_id][:artist], in_mapping[song_id][:song]]
end
end
@ -1518,6 +1644,7 @@ module JamRuby
break
end
end
def create_masters
iterate_song_storage do |metadata, metalocation|
next if metadata.nil?
@ -1584,6 +1711,38 @@ module JamRuby
importer
end
# hunts for the most recent .aac, .mp3, or .ogg file
def synchronize_preview_dev(jam_track)
importer = JamTrackImporter.new
importer.name = jam_track.name
importer.synchronize_preview_dev(jam_track)
importer.finish('success', nil)
importer
end
def synchronize_jamtrack_aac_preview(jam_track)
importer = JamTrackImporter.new
importer.name = jam_track.name
track = jam_track.master_track
if track
Dir.mktmpdir do |tmp_dir|
ogg_44100 = File.join(tmp_dir, 'input.ogg')
private_s3_manager.download(track.url_by_sample_rate(44), ogg_44100)
ogg_44100_digest = ::Digest::MD5.file(ogg_44100)
if importer.synchronize_aac_preview(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_preview(jam_track)
importer = JamTrackImporter.new
importer.name = jam_track.name
@ -1606,6 +1765,30 @@ module JamRuby
importer
end
def synchronize_previews_dev
importers = []
JamTrack.all.each do |jam_track|
importers << synchronize_preview_dev(jam_track)
end
@@log.info("SUMMARY")
@@log.info("-------")
importers.each do |importer|
if importer
if importer.reason == "success" || importer.reason == "no_preview_start_time"
@@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_previews
importers = []
@ -1632,6 +1815,33 @@ module JamRuby
end
end
def synchronize_jamtrack_aac_previews
importers = []
JamTrack.all.each do |jam_track|
importers << synchronize_jamtrack_aac_preview(jam_track)
end
@@log.info("SUMMARY")
@@log.info("-------")
importers.each do |importer|
if importer
if importer.reason == "success" || importer.reason == "jam_track_exists" || importer.reason == "other_processing"
@@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_jamtrack_master_previews
importers = []
@ -1883,11 +2093,11 @@ module JamRuby
genre4 = value[:genre4]
genre5 = value[:genre5]
genres << genre1.downcase.strip if genre1
genres << genre2.downcase.strip if genre2
genres << genre3.downcase.strip if genre3
genres << genre4.downcase.strip if genre4
genres << genre5.downcase.strip if genre5
genres << genre1.downcase.strip if genre1
genres << genre2.downcase.strip if genre2
genres << genre3.downcase.strip if genre3
genres << genre4.downcase.strip if genre4
genres << genre5.downcase.strip if genre5
value[:genres] = genres
end

View File

@ -121,6 +121,10 @@ module JamRuby
s3_bucket.objects[filename].exists?
end
def object(filename)
s3_bucket.objects[filename]
end
def length(filename)
s3_bucket.objects[filename].content_length
end

View File

@ -15,7 +15,7 @@ module JamRuby
before_validation(:on => :create) do
self.created_at ||= Time.now
self.id = SecureRandom.uuid
self.uri = "dump/#{self.id}-#{self.created_at.to_i}"
self.uri = "dumps/#{created_at.strftime('%Y-%m-%d')}/#{self.id}"
end
def user_email

View File

@ -451,7 +451,7 @@ module JamRuby
end
def mixdowns_for_user(user)
JamTrackMixdown.where(user_id: user.id, jam_track_id: self.id).order('created_at DESC')
JamTrackMixdown.where(user_id: user.id).where(jam_track_id: self.id)
end
def short_plan_code
@ -466,7 +466,6 @@ module JamRuby
def generate_slug
self.slug = sluggarize(original_artist) + '-' + sluggarize(name)
end
end

View File

@ -16,7 +16,7 @@ module JamRuby
validates :jam_track, presence: true
validates :settings, presence: true
validates_uniqueness_of :name, scope: :jam_track_id
validates_uniqueness_of :name, scope: :user_id
validate :verify_settings
validate :verify_max_mixdowns
@ -49,10 +49,13 @@ module JamRuby
# the user has to specify at least at least one tweak to volume, speed, pitch, pan. otherwise there is nothing to do
tweaked = false
all_quiet = true
parsed = JSON.parse(self.settings)
specified_track_count = parsed["tracks"] ? parsed["tracks"].length : 0
tweaked = false
all_quiet = jam_track.stem_tracks.length == 0 ? false : jam_track.stem_tracks.length == specified_track_count # we already say 'all_quiet is false' if the user did not specify as many tracks as there are on the JamTrack, because omission implies 'include this track'
if parsed["speed"]
tweaked = true
end
@ -83,7 +86,7 @@ module JamRuby
if all_quiet
errors.add(:settings, 'are all muted')
end
if !tweaked
if !tweaked && !parsed['full']
errors.add(:settings, 'have nothing specified')
end

View File

@ -37,19 +37,15 @@ module JamRuby
MAX_JAM_TRACK_DOWNLOADS = 1000
def estimated_queue_time
def self.estimated_queue_time
jam_track_signing_count = JamTrackRight.where(queued: true).count
mixdowns = JamTrackMixdownPackage.select('count(queued) as queue_count, count(speed_pitched) as speed_pitch_count').where(queued: true).first
total_mixdowns = mixdowns['queue_count']
slow_mixdowns = mixdowns['speed_pitch_count']
mixdowns = JamTrackMixdownPackage.unscoped.select('count(CASE WHEN queued THEN 1 ELSE NULL END) as queue_count, count(CASE WHEN speed_pitched THEN 1 ELSE NULL END) as speed_pitch_count').where(queued: true).first
total_mixdowns = mixdowns['queue_count'].to_i
slow_mixdowns = mixdowns['speed_pitch_count'].to_i
fast_mixdowns = total_mixdowns - slow_mixdowns
guess = APP_CONFIG.estimated_jam_track_time * jam_track_signing_count + APP_CONFIG.estimated_fast_mixdown_time * fast_mixdowns + APP_CONFIG.estimated_slow_mixdown_time * slow_mixdowns
# knock off about a minute based on number of nodes
guess = guess - ((APP_CONFIG.num_signing_nodes - 1) * 60)
guess = 0 if guess < 0
Stats.write('web.jam_track.queue_time', {value: guess / 60.0, jam_tracks: jam_track_signing_count, slow_mixdowns: slow_mixdowns, fast_mixdowns: fast_mixdowns})
guess
end
@ -66,6 +62,7 @@ module JamRuby
def self.create(mixdown, file_type, sample_rate, encrypt_type)
package = JamTrackMixdownPackage.new
package.speed_pitched = mixdown.will_pitch_shift?
package.jam_track_mixdown = mixdown
package.file_type = file_type
package.sample_rate = sample_rate
@ -148,11 +145,14 @@ module JamRuby
self.signing_queued_at = Time.now
self.signing_started_at = nil
self.last_signed_at = nil
self.queued = true
self.save
queue_time = JamTrackMixdownPackage.estimated_queue_time
# is_pitch_speed_shifted?
Resque.enqueue(JamTrackMixdownPackager, self.id)
true
return queue_time
rescue Exception => e
puts "e: #{e}"
# implies redis is down. we don't update started_at by bailing out here
@ -166,8 +166,7 @@ module JamRuby
if state == 'SIGNED' || state == 'SIGNING' || state == 'QUEUED'
false
else
enqueue
true
return enqueue
end
end
@ -233,10 +232,10 @@ module JamRuby
def self.stats
stats = {}
result = JamTrackMixdownPackage.select('count(id) as total, count(CASE WHEN signing THEN 1 ELSE NULL END) as signing_count').first
result = JamTrackMixdownPackage.unscoped.select('count(id) as total, count(CASE WHEN signing THEN 1 ELSE NULL END) as signing_count')
stats['count'] = result['total'].to_i
stats['signing_count'] = result['signing_count'].to_i
stats['count'] = result[0]['total'].to_i
stats['signing_count'] = result[0]['signing_count'].to_i
stats
end

View File

@ -66,6 +66,7 @@ module JamRuby
def finish_errored(error_reason, error_detail, sample_rate)
self.last_signed_at = Time.now
self.queued = false
self.error_count = self.error_count + 1
self.error_reason = error_reason
self.error_detail = error_detail
@ -85,6 +86,7 @@ module JamRuby
def finish_sign(length, md5, bitrate)
self.last_signed_at = Time.now
self.queued = false
if bitrate==48
self.length_48 = length
self.md5_48 = md5
@ -120,7 +122,7 @@ module JamRuby
def enqueue(sample_rate=48)
begin
JamTrackRight.where(:id => self.id).update_all(:signing_queued_at => Time.now, :signing_started_at_44 => nil, :signing_started_at_48 => nil, :last_signed_at => nil)
JamTrackRight.where(:id => self.id).update_all(:signing_queued_at => Time.now, :signing_started_at_44 => nil, :signing_started_at_48 => nil, :last_signed_at => nil, :queued => true)
Resque.enqueue(JamTracksBuilder, self.id, sample_rate)
true
rescue Exception => e

View File

@ -49,7 +49,11 @@ module JamRuby
# 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}"
"#{preview_directory}/#{original_name}"
end
def preview_directory
"jam_track_previews/#{jam_track.original_artist}/#{jam_track.name}"
end
def has_preview?
@ -58,7 +62,16 @@ module JamRuby
# 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]
case media_type
when 'ogg'
url = self[:preview_url]
when 'mp3'
url = self[:preview_mp3_url]
when 'aac'
url = self[:preview_aac_url]
else
raise "unknown media_type #{media_type}"
end
if url
s3_public_manager.public_url(url,{ :secure => true})
else
@ -154,6 +167,7 @@ module JamRuby
# input is the original ogg file for the track. tmp_dir is where this code can safely generate output stuff and have it cleaned up later
def process_preview(input, tmp_dir)
raise "Does not include AAC generation. Must be updated before used."
uuid = SecureRandom.uuid
output = File.join(tmp_dir, "#{uuid}.ogg")
output_mp3 = File.join(tmp_dir, "#{uuid}.mp3")
@ -176,7 +190,6 @@ module JamRuby
# now create mp3 off of ogg preview
convert_mp3_cmd = "#{APP_CONFIG.ffmpeg_path} -i \"#{output}\" -ab 192k \"#{output_mp3}\""
@@log.debug("converting to mp3 using: " + convert_mp3_cmd)
convert_output = `#{convert_mp3_cmd}`

View File

@ -205,7 +205,7 @@ module JamRuby
end
# Start recording a session.
def self.start(music_session, owner)
def self.start(music_session, owner, record_video: false)
recording = nil
# Use a transaction and lock to avoid races.
music_session.with_lock do
@ -213,6 +213,7 @@ module JamRuby
recording.music_session = music_session
recording.owner = owner
recording.band = music_session.band
recording.video = record_video
if recording.save
GoogleAnalyticsEvent.report_band_recording(recording.band)

View File

@ -73,6 +73,7 @@ module JamRuby
@mixdown_package.signing = true
@mixdown_package.should_retry = false
@mixdown_package.last_step_at = last_step_at
@mixdown_package.queued = false
@mixdown_package.save
SubscriptionMessage.mixdown_signing_job_change(@mixdown_package)

View File

@ -42,7 +42,7 @@ module JamRuby
signing_started_model_symbol = bitrate == 48 ? :signing_started_at_48 : :signing_started_at_44
signing_state_symbol = bitrate == 48 ? :signing_48 : :signing_44
last_step_at = Time.now
JamTrackRight.where(:id => @jam_track_right.id).update_all(signing_started_model_symbol => signing_started_at, :should_retry => false, packaging_steps: total_steps, current_packaging_step: 0, last_step_at: last_step_at, signing_state_symbol => true)
JamTrackRight.where(:id => @jam_track_right.id).update_all(signing_started_model_symbol => signing_started_at, :should_retry => false, packaging_steps: total_steps, current_packaging_step: 0, last_step_at: last_step_at, signing_state_symbol => true, queued: false)
# because we are skipping 'after_save', we have to keep the model current for the notification. A bit ugly...
@jam_track_right.current_packaging_step = 0
@jam_track_right.packaging_steps = total_steps
@ -50,6 +50,7 @@ module JamRuby
@jam_track_right[signing_state_symbol] = true
@jam_track_right.should_retry = false
@jam_track_right.last_step_at = Time.now
@jam_track_right.queued = false
SubscriptionMessage.jam_track_signing_job_change(@jam_track_right)
JamRuby::JamTracksManager.save_jam_track_right_jkz(@jam_track_right, self.bitrate)

View File

@ -24,6 +24,11 @@ module JamRuby
def perform
# this needs more testing
# let's make sure jobs don't stay falsely queued for too long. 1 hour seems more than enough
JamTrackRight.where("queued = true AND (NOW() - signing_queued_at > '1 hour'::INTERVAL OR NOW() - updated_at > '1 hour'::INTERVAL)").update_all(queued:false)
JamTrackMixdownPackage.unscoped.where("queued = true AND (NOW() - signing_queued_at > '1 hour'::INTERVAL OR NOW() - updated_at > '1 hour'::INTERVAL)").update_all(queued:false)
return
#JamTrackRight.ready_to_clean.each do |jam_track_right|
# log.debug("deleting files for jam_track_right #{jam_track_right.id}")

View File

@ -0,0 +1,82 @@
require 'spec_helper'
describe JamTrackMixdown do
let(:user) {FactoryGirl.create(:user)}
let(:jam_track) {FactoryGirl.create(:jam_track)}
let(:settings) { {speed:5} }
it "can be created (factory girl)" do
mixdown = FactoryGirl.create(:jam_track_mixdown)
mixdown = JamTrackMixdown.find(mixdown.id)
mixdown.settings.should eq('{"speed":5}')
end
it "can be created" do
mixdown = JamTrackMixdown.create('abc', 'description', user, jam_track, settings)
mixdown.errors.any?.should == false
end
it "index" do
query, start, count = JamTrackMixdown.index({id: jam_track}, user)
query.length.should eq(0)
start.should be_nil
count.should eq(0)
mixdown = FactoryGirl.create(:jam_track_mixdown, user: user, jam_track: jam_track)
query, start, count = JamTrackMixdown.index({id: jam_track}, user)
query[0].should eq(mixdown)
start.should be_nil
count.should eq(1)
end
describe "settings" do
it "validates empty settings" do
invalid = FactoryGirl.build(:jam_track_mixdown, settings: {}.to_json)
invalid.save
invalid.errors.any?.should be_true
invalid.errors["settings"].should eq(["have nothing specified"])
end
it "validates speed numeric" do
invalid = FactoryGirl.build(:jam_track_mixdown, settings: {"speed": "5"}.to_json)
invalid.save
invalid.errors.any?.should be_true
invalid.errors["settings"].should eq(["has non-integer speed"])
end
it "validates pitch numeric" do
invalid = FactoryGirl.build(:jam_track_mixdown, settings: {"pitch": "5"}.to_json)
invalid.save
invalid.errors.any?.should be_true
invalid.errors["settings"].should eq(["has non-integer pitch"])
end
it "validates speed not-float" do
invalid = FactoryGirl.build(:jam_track_mixdown, settings: {"speed": 5.5}.to_json)
invalid.save
invalid.errors.any?.should be_true
invalid.errors["settings"].should eq(["has non-integer speed"])
end
it "validates pitch not-float" do
invalid = FactoryGirl.build(:jam_track_mixdown, settings: {"pitch": 10.5}.to_json)
invalid.save
invalid.errors.any?.should be_true
invalid.errors["settings"].should eq(["has non-integer pitch"])
end
end
mixdown.settings.should eq('{}')
end
it "can be created" do
mixdown = JamTrackMixdown.create('abc', user, jam_track, {})
mixdown.errors.any?.should == false
end
end

View File

@ -12,7 +12,6 @@ describe JamTrackMixdownPackage do
package = JamTrackMixdownPackage.create(mixdown, JamTrackMixdownPackage::FILE_TYPE_OGG, 48, 'jkz')
puts package.errors.inspect
package.errors.any?.should == false
end
@ -34,12 +33,12 @@ describe JamTrackMixdownPackage do
end
it "signing" do
package = FactoryGirl.create(:jam_track_mixdown_package, signing_started_at: Time.now, packaging_steps: 3, current_packaging_step:0, last_step_at:Time.now)
package = FactoryGirl.create(:jam_track_mixdown_package, signing:true, signing_started_at: Time.now, packaging_steps: 3, current_packaging_step:0, last_step_at:Time.now)
package.signing_state.should eq('SIGNING')
end
it "signing timeout" do
package = FactoryGirl.create(:jam_track_mixdown_package, signing_started_at: Time.now - 100, packaging_steps: 3, current_packaging_step:0, last_step_at:Time.now)
package = FactoryGirl.create(:jam_track_mixdown_package, signing: true, signing_started_at: Time.now - (APP_CONFIG.signing_job_signing_max_time + 1), packaging_steps: 3, current_packaging_step:0, last_step_at:Time.now)
package.signing_state.should eq('SIGNING_TIMEOUT')
end
@ -49,7 +48,7 @@ describe JamTrackMixdownPackage do
end
it "signing timeout" do
package = FactoryGirl.create(:jam_track_mixdown_package, signing_queued_at: Time.now - (APP_CONFIG.signing_job_queue_max_time + 1))
package = FactoryGirl.create(:jam_track_mixdown_package, signing_queued_at: Time.now - (APP_CONFIG.mixdown_job_queue_max_time + 1))
package.signing_state.should eq('QUEUED_TIMEOUT')
end
end
@ -74,6 +73,30 @@ describe JamTrackMixdownPackage do
end
describe "estimated_queue_time" do
it "succeeds with no data" do
JamTrackMixdownPackage.estimated_queue_time.should eq(0)
end
it "mixdown packages of different sorts" do
package = FactoryGirl.create(:jam_track_mixdown_package, speed_pitched: true)
JamTrackMixdownPackage.estimated_queue_time.should eq(0)
package.queued = true
package.save!
JamTrackMixdownPackage.estimated_queue_time.should eq(APP_CONFIG.estimated_slow_mixdown_time * 1)
package.speed_pitched = false
package.save!
JamTrackMixdownPackage.estimated_queue_time.should eq(APP_CONFIG.estimated_fast_mixdown_time * 1)
right = FactoryGirl.create(:jam_track_right)
JamTrackMixdownPackage.estimated_queue_time.should eq(APP_CONFIG.estimated_fast_mixdown_time * 1)
right.queued = true
right.save!
JamTrackMixdownPackage.estimated_queue_time.should eq(APP_CONFIG.estimated_fast_mixdown_time * 1 + APP_CONFIG.estimated_jam_track_time * 1)
end
end
end

View File

@ -179,7 +179,7 @@ def app_config
end
def signing_job_queue_max_time
20 # 20 seconds
600 # 20 seconds
end
def one_free_jamtrack_per_user
@ -226,6 +226,18 @@ def app_config
2
end
def signing_job_signing_max_time
300
end
def mixdown_job_queue_max_time
600
end
def mixdown_step_max_time
300
end
private
def audiomixer_workspace_path

View File

@ -99,7 +99,7 @@ gem 'react-rails-img'
source 'https://rails-assets.org' do
gem 'rails-assets-reflux'
gem 'rails-assets-classnames'
gem 'rails-assets-react-select'
gem 'rails-assets-react-select', '0.6.7'
end
#group :development, :production do

Binary file not shown.

After

Width:  |  Height:  |  Size: 606 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 642 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 806 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 837 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -23,6 +23,7 @@
var mode = null;
// heartbeat
var startHeartbeatTimeout = null;
var heartbeatInterval = null;
var heartbeatMS = null;
var connection_expire_time = null;
@ -79,6 +80,7 @@
function initiateReconnect(activeElementVotes, in_error) {
var initialConnect = !!activeElementVotes;
console.log("activeElementVotes", activeElementVotes)
freezeInteraction = activeElementVotes && ((activeElementVotes.dialog && activeElementVotes.dialog.freezeInteraction === true) || (activeElementVotes.screen && activeElementVotes.screen.freezeInteraction === true));
if (in_error) {
@ -104,6 +106,12 @@
heartbeatInterval = null;
}
// stop the heartbeat start delay from happening
if (startHeartbeatTimeout != null) {
clearTimeout(startHeartbeatTimeout);
startHeartbeatTimeout = null;
}
// stop checking for heartbeat acks
if (heartbeatAckCheckInterval != null) {
clearTimeout(heartbeatAckCheckInterval);
@ -236,9 +244,41 @@
heartbeatMS = payload.heartbeat_interval * 1000;
connection_expire_time = payload.connection_expire_time * 1000;
logger.info("loggedIn(): clientId=" + app.clientId + " heartbeat=" + payload.heartbeat_interval + "s expire_time=" + payload.connection_expire_time + 's');
heartbeatInterval = context.setInterval(_heartbeat, heartbeatMS);
heartbeatAckCheckInterval = context.setInterval(_heartbeatAckCheck, 1000);
lastHeartbeatAckTime = new Date(new Date().getTime() + heartbeatMS); // add a little forgiveness to server for initial heartbeat
// add some randomness to help move heartbeats apart from each other
// send 1st heartbeat somewhere between 0 - 0.5 of the connection expire time
var randomStartTime = connection_expire_time * (Math.random() / 2)
if (startHeartbeatTimeout) {
logger.warn("start heartbeat timeout is active; should be null")
clearTimeout(startHeartbeatTimeout)
}
if (heartbeatInterval != null) {
logger.warn("heartbeatInterval is active; should be null")
clearInterval(heartbeatInterval);
heartbeatInterval = null;
}
if (heartbeatAckCheckInterval != null) {
logger.warn("heartbeatAckCheckInterval is active; should be null")
clearInterval(heartbeatAckCheckInterval);
heartbeatAckCheckInterval = null;
}
startHeartbeatTimeout = setTimeout(function() {
if(server.connected) {
heartbeatInterval = context.setInterval(_heartbeat, heartbeatMS);
heartbeatAckCheckInterval = context.setInterval(_heartbeatAckCheck, 1000);
lastHeartbeatAckTime = new Date(new Date().getTime() + heartbeatMS); // add a little forgiveness to server for initial heartbeat
}
}, randomStartTime)
logger.info("starting heartbeat timer in " + randomStartTime/1000 + 's')
connectDeferred.resolve();
$self.triggerHandler(EVENTS.CONNECTION_UP)
@ -295,6 +335,11 @@
logger.debug(payload.error_code + ": no longer reconnecting")
server.noReconnect = true; // stop trying to log in!!
}
else if (payload.error_code == 'no_reconnect') {
logger.debug(payload.error_code + ": no longer reconnecting")
server.noReconnect = true; // stop trying to log in!!
context.JK.Banner.showAlert("Misbehaved Client", "Please restart your application in order to continue using JamKazam.")
}
}
///////////////////
@ -384,7 +429,7 @@
}
function formatDelaySecs(secs) {
return $('<span class="countdown-seconds"><span class="countdown">' + secs + '</span> ' + (secs == 1 ? ' second.<span style="visibility:hidden">s</span>' : 'seconds.') + '</span>');
return $('<span class="countdown-seconds"><span class="countdown">' + secs + '</span> ' + (secs == 1 ? ' second.<span style="visibility:hidden">s</span>' : 'seconds.') + '</span>');
}
function setCountdown($parent) {

View File

@ -19,7 +19,7 @@ context.JK.AccountJamTracks = class AccountJamTracks
@screen = $('#account-jamtracks')
beforeShow:() =>
rest.getPurchasedJamTracks({})
rest.getPurchasedJamTracks({limit: 40})
.done(@populateJamTracks)
.fail(@app.ajaxError);

View File

@ -13,6 +13,13 @@
// remove all display errors
$('#recording-finished-dialog form .error-text').remove()
$('#recording-finished-dialog form .error').removeClass("error")
console.log("save video?", recording)
if(recording.video) {
$dialog.find('.save-video').show()
}
else {
$dialog.find('.save-video').hide()
}
removeGoogleLoginErrors()
}
@ -103,6 +110,14 @@
}
function afterHide() {
if(recording && recording.video) {
var name = $('#recording-finished-dialog form input[name=name]').val();
name = name.replace(/[^A-Za-z0-9\-\ ]/g, '');
var keep = $('#recording-finished-dialog form input[name=save_video]').is(':checked')
logger.debug("VideoDecision rid:" + recording.id + ", name=" + name + ", keep=" + keep)
context.jamClient.VideoDecision(recording.id, name, keep)
}
recording = null;
playbackControls.stopMonitor();
context.jamClient.ClosePreviewRecording();

View File

@ -39,6 +39,7 @@
var $self = $(this);
var disabled = false;
var playbackPlaying = false;
var playbackDurationMs = 0;
var playbackPositionMs = 0;
@ -173,6 +174,11 @@
}
$playButton.on('click', function (e) {
if (disabled) {
logger.debug("PlaybackControls are disabled; ignoring start button")
return;
}
startPlay();
return false;
});
@ -484,6 +490,10 @@
playbackPlaying = false;
}
function setDisabled(_disabled) {
disabled = _disabled;
}
this.update = update;
this.setPlaybackMode = setPlaybackMode;
this.startMonitor = startMonitor;
@ -492,6 +502,7 @@
this.onPlayStopEvent = onPlayStopEvent;
this.onPlayStartEvent = onPlayStartEvent;
this.onPlayPauseEvent = onPlayPauseEvent;
this.setDisabled = setDisabled;
return this;
}

View File

@ -19,9 +19,11 @@ MixerActions = reactContext.MixerActions
MediaPlaybackStore = reactContext.MediaPlaybackStore
SessionActions = reactContext.SessionActions
MediaPlaybackActions = reactContext.MediaPlaybackActions
JamTrackStore = reactContext.JamTrackStore
mixins.push(Reflux.listenTo(MixerStore,"onInputsChanged"))
mixins.push(Reflux.listenTo(MediaPlaybackStore, 'onMediaStateChanged'))
mixins.push(Reflux.listenTo(JamTrackStore, 'onJamTrackStateChanged'))
@MediaControls = React.createClass({
@ -29,6 +31,10 @@ mixins.push(Reflux.listenTo(MediaPlaybackStore, 'onMediaStateChanged'))
mixins: mixins
tempos : [ 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 63, 66, 69, 72, 76, 80, 84, 88, 92, 96, 100, 104, 108, 112, 116, 120, 126, 132, 138, 144, 152, 160, 168, 176, 184, 192, 200, 208 ]
onJamTrackStateChanged: (jamTrackState) ->
@monitorControls(@state.controls, @state.mediaSummary, jamTrackState)
@setState({jamTrackState: jamTrackState})
onMediaStateChanged: (changes) ->
if changes.playbackStateChanged
if @state.controls?
@ -53,7 +59,7 @@ mixins.push(Reflux.listenTo(MediaPlaybackStore, 'onMediaStateChanged'))
mediaSummary = mixers.mediaSummary
metro = mixers.metro
@monitorControls(@state.controls, mediaSummary)
@monitorControls(@state.controls, mediaSummary, @state.jamTrackState)
@setState({mediaSummary: mediaSummary, metro: metro})
@updateMetronomeDetails(metro, @state.initializedMetronomeControls)
@ -69,10 +75,10 @@ mixins.push(Reflux.listenTo(MediaPlaybackStore, 'onMediaStateChanged'))
logger.debug("settingcricket", mode)
$root.find('#metronome-playback-select').metronomeSetPlaybackMode(mode)
monitorControls: (controls, mediaSummary) ->
monitorControls: (controls, mediaSummary, jamTrackState) ->
if mediaSummary.mediaOpen || mediaSummary.jamTrack?
if mediaSummary.jamTrack?
if mediaSummary.mediaOpen || mediaSummary.jamTrack? || jamTrackState?.jamTrack?
if mediaSummary.jamTrackOpen? || mediaSummary.jamTrack? || jamTrackState?.jamTrack?
controls.startMonitor(PLAYBACK_MONITOR_MODE.JAMTRACK)
else if mediaSummary.backingTrackOpen
controls.startMonitor(PLAYBACK_MONITOR_MODE.MEDIA_FILE)
@ -200,13 +206,19 @@ mixins.push(Reflux.listenTo(MediaPlaybackStore, 'onMediaStateChanged'))
$root = jQuery(this.getDOMNode())
controls = context.JK.PlaybackControls($root, {mediaActions: MediaPlaybackActions})
controls.setDisabled(@props.disabled)
mediaSummary = MixerStore.mixers.mediaSummary
metro = MixerStore.mixers.metro
jamTrackState = JamTrackStore.getState()
@monitorControls(controls, mediaSummary)
@monitorControls(controls, mediaSummary, jamTrackState)
@tryPrepareMetronome(metro)
@setState({mediaSummary: mediaSummary, controls: controls, metro: metro})
@setState({mediaSummary: mediaSummary, controls: controls, metro: metro, jamTrackState: jamTrackState})
componentWillUpdate: (nextProps) ->
@state.controls.setDisabled(nextProps.disabled) if @state.controls?
})

View File

@ -16,8 +16,10 @@ if window.opener?
if accessOpener
AppActions = window.opener.AppActions
SessionActions = window.opener.SessionActions
MixerActions = window.opener.MixerActions
MixerStore = window.opener.MixerStore
JamTrackActions = window.opener.JamTrackActions
JamTrackMixdownActions = window.opener.JamTrackMixdownActions
#JamTrackMixdownStore = window.opener.JamTrackMixdownStore
@ -33,10 +35,8 @@ mixins.push(Reflux.listenTo(JamTrackStore, 'onJamTrackChanged'))
mixins: mixins
onMixersChanged: (sessionMixers) ->
updateFromMixerHelper: (mixers, session) ->
session = sessionMixers.session
mixers = sessionMixers.mixers
# the backend delete/adds the metronome rapidly when the user hits play. this is custom code to deal with that
@ -49,16 +49,20 @@ mixins.push(Reflux.listenTo(JamTrackStore, 'onJamTrackChanged'))
metronome: mixers.metronome
recordingName: mixers.recordingName()
jamTrackName: mixers.jamTrackName()
jamTrackMixdown: session.jamTrackMixdown()
@setState(media: state, downloadingJamTrack: session.downloadingJamTrack)
return {media: state, downloadingJamTrack: session.downloadingJamTrack}
onMixersChanged: (sessionMixers) ->
session = sessionMixers.session
mixers = sessionMixers.mixers
@setState(@updateFromMixerHelper(mixers, session))
onMediaStateChanged: (changes) ->
if changes.currentTimeChanged && @root?
@setState({time: changes.time})
onJamTrackMixdownChanged: (changes) ->
@setState({mixdown: changes})
onJamTrackChanged: (changes) ->
logger.debug("PopupMediaControls: jamtrack changed", changes)
@setState({jamTrackState: changes})
@ -69,19 +73,32 @@ mixins.push(Reflux.listenTo(JamTrackStore, 'onJamTrackChanged'))
SessionActions.showNativeMetronomeGui()
getInitialState: () ->
{
if accessOpener
state = @updateFromMixerHelper(MixerStore.mixers, MixerStore.session)
state.jamTrackState = JamTrackStore.getState()
return state
else
return {
media: @props.media,
mixdown: @props.mixdown,
jamTrackState: @props.jamTrackState,
creatingMixdown: false,
createMixdownErrors: null,
editingMixdownId: null,
downloadingJamTrack: @props.downloadingJamTrack
downloadingJamTrack: @props.downloadingJamTrack,
jamTrackMixdown: {}
}
close: () ->
window.close()
help: (e) ->
e.preventDefault()
AppActions.openExternalUrl($(e.target).attr('href'))
render: () ->
@ -95,235 +112,268 @@ mixins.push(Reflux.listenTo(JamTrackStore, 'onJamTrackChanged'))
mediaName = @state.media.recordedTracks[0].recordingName
closeLinkText = 'close recording'
header = `<h3>{mediaType}: {mediaName}</h3>`
else if @state.jamTrackState.jamTrack?
jamTrack = @state.jamTrackState.jamTrack
mediaType = "JamTrack"
mediaName = jamTrack.name
closeLinkText = 'CLOSE JAMTRACK'
else if @state.media.mediaSummary.jamTrackOpen || @state.jamTrackState.jamTrack?
if @state.media.mediaSummary.isOpener || @state.jamTrackState.jamTrack?
# if you opened the JamTrack, then you get all the good info
jamTrack = @state.jamTrackState.jamTrack
mediaType = "JamTrack"
mediaName = jamTrack.name
closeLinkText = 'CLOSE JAMTRACK'
helpLink = 'https://jamkazam.desk.com/customer/portal/articles/2138903-using-custom-mixes-to-slow-tempo-change-pitch'
selectedMixdown = jamTrack.activeMixdown
selectedMixdown = jamTrack.activeMixdown
if selectedMixdown?
jamTrackTypeHeader = 'Custom Mix'
if selectedMixdown?
jamTrackTypeHeader = 'Custom Mix'
disabled = true
if selectedMixdown.client_state?
switch selectedMixdown.client_state
when 'cant_open'
disabled = true
if selectedMixdown.client_state?
switch selectedMixdown.client_state
when 'cant_open'
customMixName = `<h5>{selectedMixdown.name}<img src="/assets/content/icon-mix-fail@2X.png" /></h5>`
when 'keying_timeout'
customMixName = `<h5>{selectedMixdown.name}<img src="/assets/content/icon-mix-fail@2X.png" /></h5>`
when 'download_fail'
customMixName = `<h5>{selectedMixdown.name}<img src="/assets/content/icon-mix-fail@2X.png" /></h5>`
when 'keying'
customMixName = `<h5>Loading selected mix... <img src="/assets/shared/spinner.gif" /></h5>`
when 'downloading'
customMixName = `<h5>Loading selected mix... <img src="/assets/shared/spinner.gif" /></h5>`
when 'ready'
customMixName = `<h5>{selectedMixdown.name}</h5>`
disabled = false
else
if selectedMixdown.myPackage
customMixName = `<h5>Creating mixdown... <img src="/assets/shared/spinner.gif" /></h5>`
else
customMixName = `<h5>{selectedMixdown.name}<img src="/assets/content/icon-mix-fail@2X.png" /></h5>`
when 'keying_timeout'
customMixName = `<h5>{selectedMixdown.name}<img src="/assets/content/icon-mix-fail@2X.png" /></h5>`
when 'download_fail'
customMixName = `<h5>{selectedMixdown.name}<img src="/assets/content/icon-mix-fail@2X.png" /></h5>`
when 'keying'
customMixName = `<h5>Loading selected mix... <img src="/assets/shared/spinner.gif" /></h5>`
when 'downloading'
customMixName = `<h5>Loading selected mix... <img src="/assets/shared/spinner.gif" /></h5>`
when 'ready'
customMixName = `<h5>{selectedMixdown.name}</h5>`
disabled = false
else
customMixName = `<h5>Creating mixdown... <img src="/assets/shared/spinner.gif" /></h5>`
if SessionStore.downloadingJamTrack
downloader = `<img src="/assets/shared/spinner.gif" />`
else
if SessionStore.downloadingJamTrack
downloader = `<img src="/assets/shared/spinner.gif" />`
jamTrackTypeHeader = `<span>Full JamTrack {downloader}</span>`
jamTrackTypeHeader = `<span>Full JamTrack {downloader}</span>`
header = `
<div className="header">
<h3>{mediaType}: {mediaName}</h3>
<h4>{jamTrackTypeHeader}</h4>
{customMixName}
</div>`
header = `
<div className="header">
<h3>{mediaType}: {mediaName}</h3>
<h4>{jamTrackTypeHeader}</h4>
{customMixName}
</div>`
myMixes = null
if @state.showMyMixes
myMixdowns = []
myMixes = null
if @state.showMyMixes
myMixdowns = []
boundPlayClick = this.jamTrackPlay.bind(this, jamTrack);
boundPlayClick = this.jamTrackPlay.bind(this, jamTrack);
active = jamTrack.last_mixdown_id == null
myMixdowns.push `
<div key="full-track" className={classNames({'full-track': true, 'mixdown-display': true, 'active' : active})}>
<div className="mixdown-name">
Full JamTrack
</div>
<div className="mixdown-actions">
<img src="/assets/content/icon_open@2X.png" className="mixdown-play" onClick={boundPlayClick}/>
</div>
</div>`
for mixdown in jamTrack.mixdowns
boundPlayClick = this.mixdownPlay.bind(this, mixdown);
boundEditClick = this.mixdownEdit.bind(this, mixdown);
boundSaveClick = this.mixdownSave.bind(this, mixdown);
boundDeleteClick = this.mixdownDelete.bind(this, mixdown);
boundErrorClick = this.mixdownError.bind(this, mixdown);
boundEditKeydown = this.onEditKeydown.bind(this, mixdown);
mixdown_package = mixdown.myPackage
active = mixdown.id == jamTrack.last_mixdown_id
editing = mixdown.id == @state.editingMixdownId
# if there is a package, check it's state; otherwise let the user enqueue it
if mixdown_package
switch mixdown_package.signing_state
when 'QUIET_TIMEOUT'
action = `<img src="/assets/content/icon-mix-fail@2X.png" className="mixdown-play" onClick={boundErrorClick}/>`
when 'QUIET'
action = `<img src="/assets/shared/spinner.gif" className="mixdown-play"/>`
when 'QUEUED'
action = `<img src="/assets/shared/spinner.gif" className="mixdown-play"/>`
when 'QUEUED_TIMEOUT'
action = `<img src="/assets/content/icon-mix-fail@2X.png" className="mixdown-play" onClick={boundErrorClick}/>`
when 'SIGNING'
action = `<img src="/assets/shared/spinner.gif" className="mixdown-play"/>`
when 'SIGNING_TIMEOUT'
action = `<img src="/assets/content/icon-mix-fail@2X.png" className="mixdown-play" onClick={boundErrorClick}/>`
when 'SIGNED'
action = `<img src="/assets/content/icon_open@2X.png" className="mixdown-play" onClick={boundPlayClick}/>`
when 'ERROR'
action = `<img src="/assets/content/icon-mix-fail@2X.png" className="mixdown-play" onClick={boundErrorClick}/>`
else
action = `<img src="/assets/content/icon-mix-fail@2X.png" className="mixdown-play" onClick={boundErrorClick}/>`
if editing
mixdownName = `<input className="edit-name" type="text" defaultValue={mixdown.name} onKeyDown={boundEditKeydown} />`
editIcon = `<img src="/assets/content/icon-save@2X.png" className="mixdown-edit" onClick={boundSaveClick}/>`
else
mixdownName = mixdown.name
editIcon = `<img src="/assets/content/icon-edit@2X.png" className="mixdown-edit" onClick={boundEditClick}/>`
active = jamTrack.last_mixdown_id == null
myMixdowns.push `
<div key={mixdown.id} className={classNames({'mixdown-display': true, 'active' : active})}>
<div className="mixdown-name">
{mixdownName}
</div>
<div className="mixdown-actions">
{action}
<div key="full-track" className={classNames({'full-track': true, 'mixdown-display': true, 'active' : active})}>
<div className="mixdown-name">
Full JamTrack
</div>
<div className="mixdown-actions">
<img src="/assets/content/icon_open@2X.png" className="mixdown-play" onClick={boundPlayClick}/>
</div>
</div>`
{editIcon}
for mixdown in jamTrack.mixdowns
boundPlayClick = this.mixdownPlay.bind(this, mixdown);
boundEditClick = this.mixdownEdit.bind(this, mixdown);
boundSaveClick = this.mixdownSave.bind(this, mixdown);
boundDeleteClick = this.mixdownDelete.bind(this, mixdown);
boundErrorClick = this.mixdownError.bind(this, mixdown);
boundEditKeydown = this.onEditKeydown.bind(this, mixdown);
<img src ="/assets/content/icon-delete@2X.png" className="mixdown-delete" onClick={boundDeleteClick} />
</div>
</div>`
mixdown_package = mixdown.myPackage
myMixes = `<div key="my-mixes" className="my-mixes">{myMixdowns}</div>`
active = mixdown.id == jamTrack.last_mixdown_id
mixControls = null
if @state.showCustomMixes
editing = mixdown.id == @state.editingMixdownId
nameClassData = {field: true}
if @state.createMixdownErrors?
# if there is a package, check it's state; otherwise let the user enqueue it
if mixdown_package
switch mixdown_package.signing_state
when 'QUIET_TIMEOUT'
action = `<img src="/assets/content/icon-mix-fail@2X.png" className="mixdown-play" onClick={boundErrorClick}/>`
when 'QUIET'
action = `<img src="/assets/shared/spinner.gif" className="mixdown-play"/>`
when 'QUEUED'
action = `<img src="/assets/shared/spinner.gif" className="mixdown-play"/>`
when 'QUEUED_TIMEOUT'
action = `<img src="/assets/content/icon-mix-fail@2X.png" className="mixdown-play" onClick={boundErrorClick}/>`
when 'SIGNING'
action = `<img src="/assets/shared/spinner.gif" className="mixdown-play"/>`
when 'SIGNING_TIMEOUT'
action = `<img src="/assets/content/icon-mix-fail@2X.png" className="mixdown-play" onClick={boundErrorClick}/>`
when 'SIGNED'
action = `<img src="/assets/content/icon_open@2X.png" className="mixdown-play" onClick={boundPlayClick}/>`
when 'ERROR'
action = `<img src="/assets/content/icon-mix-fail@2X.png" className="mixdown-play" onClick={boundErrorClick}/>`
else
action = `<img src="/assets/content/icon-mix-fail@2X.png" className="mixdown-play" onClick={boundErrorClick}/>`
errorHtml = context.JK.reactErrors(@state.createMixdownErrors, {name: 'Mix Name', settings: 'Settings', jam_track: 'JamTrack'})
if editing
mixdownName = `<input className="edit-name" type="text" defaultValue={mixdown.name} onKeyDown={boundEditKeydown} />`
editIcon = `<img src="/assets/content/icon-save@2X.png" className="mixdown-edit" onClick={boundSaveClick}/>`
else
mixdownName = mixdown.name
editIcon = `<img src="/assets/content/icon-edit@2X.png" className="mixdown-edit" onClick={boundEditClick}/>`
createMixClasses = classNames({'button-orange' : true, 'create-mix-btn' : true, 'disabled' : @state.creatingMixdown})
mixControls = `
<div key="create-mix" className="create-mix">
<p>Use the JamTrack controls on the session screen to set levels, mute/unmute, or pan any of the parts of the JamTrack as you like. You can also use the controls below to adjust the tempo or pitch of the JamTrack. Then give your custom mix a name, and click the Create Mix button. Please note that changing the tempo or pitch of the JamTrack may take a long time, and won't be ready right away.</p>
<div className="field">
<label>Change Tempo:</label>
<select name="mix-speed">
<option value="">No change</option>
<option value="separator-1">------------</option>
<option value="-5">Slower by 5%</option>
<option value="-10">Slower by 10%</option>
<option value="-15">Slower by 15%</option>
<option value="-20">Slower by 20%</option>
<option value="-25">Slower by 25%</option>
<option value="-30">Slower by 30%</option>
<option value="-35">Slower by 35%</option>
<option value="-40">Slower by 40%</option>
<option value="-45">Slower by 45%</option>
<option value="-50">Slower by 50%</option>
<option value="-60">Slower by 60%</option>
<option value="-70">Slower by 70%</option>
<option value="-80">Slower by 80%</option>
<option value="separator-2">------------</option>
<option value="5">Faster by 5%</option>
<option value="10">Faster by 10%</option>
<option value="15">Faster by 15%</option>
<option value="20">Faster by 20%</option>
<option value="30">Faster by 30%</option>
<option value="40">Faster by 40%</option>
<option value="50">Faster by 50%</option>
</select>
</div>
<div className="field">
<label>Change Pitch:</label>
<select name="mix-pitch">
<option value="">No change</option>
<option value="separator-1">---------------</option>
<option value="-1">Down 1 Semitone</option>
<option value="-2">Down 2 Semitones</option>
<option value="-3">Down 3 Semitones</option>
<option value="-4">Down 4 Semitones</option>
<option value="-5">Down 5 Semitones</option>
<option value="-6">Down 6 Semitones</option>
<option value="-7">Down 7 Semitones</option>
<option value="-8">Down 8 Semitones</option>
<option value="-9">Down 9 Semitones</option>
<option value="-10">Down 10 Semitones</option>
<option value="-11">Down 11 Semitones</option>
<option value="-12">Down 12 Semitones</option>
<option value="separator-2">---------------</option>
<option value="1">Up 1 Semitone</option>
<option value="2">Up 2 Semitones</option>
<option value="3">Up 3 Semitones</option>
<option value="4">Up 4 Semitones</option>
<option value="5">Up 5 Semitones</option>
<option value="6">Up 6 Semitones</option>
<option value="7">Up 7 Semitones</option>
<option value="8">Up 8 Semitones</option>
<option value="9">Up 9 Semitones</option>
<option value="10">Up 10 Semitones</option>
<option value="11">Up 11 Semitones</option>
<option value="12">Up 12 Semitones</option>
</select>
</div>
<div className={classNames(nameClassData)}>
<label>Mix Name:</label>
<input type="text" name="mix-name"/>
</div>
<div className="field">
<a className={createMixClasses} onClick={this.createMix}>CREATE MIX</a>
{errorHtml}
</div>
<div className="clearall"/>
myMixdowns.push `
<div key={mixdown.id} className={classNames({'mixdown-display': true, 'active' : active})}>
<div className="mixdown-name">
{mixdownName}
</div>
<div className="mixdown-actions">
{action}
{editIcon}
<img src ="/assets/content/icon-delete@2X.png" className="mixdown-delete" onClick={boundDeleteClick} />
</div>
</div>`
myMixes = `<div key="my-mixes" className="my-mixes">{myMixdowns}</div>`
mixControls = null
if @state.showCustomMixes
nameClassData = {field: true}
if @state.createMixdownErrors?
errorHtml = context.JK.reactErrors(@state.createMixdownErrors, {name: 'Mix Name', settings: 'Settings', jam_track: 'JamTrack'})
createMixClasses = classNames({'button-orange' : true, 'create-mix-btn' : true, 'disabled' : @state.creatingMixdown})
if !selectedMixdown?
mixControls = `
<div key="create-mix" className="create-mix">
<p>Use the JamTrack controls on the session screen to set levels, mute/unmute, or pan any of the parts of the JamTrack as you like. You can also use the controls below to adjust the tempo or pitch of the JamTrack. Then give your custom mix a name, and click the Create Mix button. Please note that changing the tempo or pitch of the JamTrack may take a long time, and won't be ready right away.</p>
<div className="field">
<label>Change Tempo:</label>
<select name="mix-speed">
<option value="">No change</option>
<option value="separator-1">------------</option>
<option value="-5">Slower by 5%</option>
<option value="-10">Slower by 10%</option>
<option value="-15">Slower by 15%</option>
<option value="-20">Slower by 20%</option>
<option value="-25">Slower by 25%</option>
<option value="-30">Slower by 30%</option>
<option value="-35">Slower by 35%</option>
<option value="-40">Slower by 40%</option>
<option value="-45">Slower by 45%</option>
<option value="-50">Slower by 50%</option>
<option value="-60">Slower by 60%</option>
<option value="-70">Slower by 70%</option>
<option value="-80">Slower by 80%</option>
<option value="separator-2">------------</option>
<option value="5">Faster by 5%</option>
<option value="10">Faster by 10%</option>
<option value="15">Faster by 15%</option>
<option value="20">Faster by 20%</option>
<option value="30">Faster by 30%</option>
<option value="40">Faster by 40%</option>
<option value="50">Faster by 50%</option>
</select>
</div>
<div className="field">
<label>Change Pitch:</label>
<select name="mix-pitch">
<option value="">No change</option>
<option value="separator-1">---------------</option>
<option value="-1">Down 1 Semitone</option>
<option value="-2">Down 2 Semitones</option>
<option value="-3">Down 3 Semitones</option>
<option value="-4">Down 4 Semitones</option>
<option value="-5">Down 5 Semitones</option>
<option value="-6">Down 6 Semitones</option>
<option value="-7">Down 7 Semitones</option>
<option value="-8">Down 8 Semitones</option>
<option value="-9">Down 9 Semitones</option>
<option value="-10">Down 10 Semitones</option>
<option value="-11">Down 11 Semitones</option>
<option value="-12">Down 12 Semitones</option>
<option value="separator-2">---------------</option>
<option value="1">Up 1 Semitone</option>
<option value="2">Up 2 Semitones</option>
<option value="3">Up 3 Semitones</option>
<option value="4">Up 4 Semitones</option>
<option value="5">Up 5 Semitones</option>
<option value="6">Up 6 Semitones</option>
<option value="7">Up 7 Semitones</option>
<option value="8">Up 8 Semitones</option>
<option value="9">Up 9 Semitones</option>
<option value="10">Up 10 Semitones</option>
<option value="11">Up 11 Semitones</option>
<option value="12">Up 12 Semitones</option>
</select>
</div>
<div className={classNames(nameClassData)}>
<label>Mix Name:</label>
<input type="text" name="mix-name"/>
</div>
<div className="field">
<a className={createMixClasses} onClick={this.createMix}>CREATE MIX</a>
{errorHtml}
</div>
<div className="clearall"/>
</div>`
else
mixControls =
`<div key="no-full-mix-open" className="create-mix not-active">
<p>To create a custom mix, you must open the Full JamTrack in the My Mixes section above.</p>
</div>`
if @state.showMyMixes
showMyMixesText = `<a onClick={this.toggleMyMixes}>hide my mixes <div className="details-arrow arrow-up" /></a>`
else
showMyMixesText = `<a onClick={this.toggleMyMixes}>show my mixes <div className="details-arrow arrow-down" /></a>`
if @state.showCustomMixes
showMixControlsText = `<a onClick={this.toggleCustomMixes}>hide mix controls <div className="details-arrow arrow-up" /></a>`
else
showMixControlsText = `<a onClick={this.toggleCustomMixes}>show mix controls <div className="details-arrow arrow-down" /></a>`
extraControls = `
<div className="extra-controls">
<h4>My Mixes {showMyMixesText}</h4>
<ReactCSSTransitionGroup transitionName="session-track-list" transitionAppear={true}>
{myMixes}
</ReactCSSTransitionGroup>
<h4 className="custom-mix-header">Create Custom Mix {showMixControlsText}</h4>
<ReactCSSTransitionGroup transitionName="session-track-list" transitionAppear={true}>
{mixControls}
</ReactCSSTransitionGroup>
</div>`
else
mediaType = "JamTrack"
mediaName = @state.media.jamTrackName
closeLinkText = 'CLOSE JAMTRACK'
# implies we have a mixdown
if @state.media.jamTrackMixdown.id?
jamTrackTypeHeader = 'Custom Mix'
else
jamTrackTypeHeader = 'Full JamTrack'
header = `
<div className="header">
<h3>{mediaType}: {mediaName}</h3>
<h4>{jamTrackTypeHeader}</h4>
{customMixName}
</div>`
if @state.showMyMixes
showMyMixesText = 'hide my mixes'
else
showMyMixesText = 'show my mixes'
if @state.showCustomMixes
showMixControlsText = 'hide mix controls'
else
showMixControlsText = 'show mix controls'
extraControls = `
<div className="extra-controls">
<h4>My Mixes <a onClick={this.toggleMyMixes}>{showMyMixesText}</a></h4>
<ReactCSSTransitionGroup transitionName="session-track-list" transitionAppear={true}>
{myMixes}
</ReactCSSTransitionGroup>
<h4 className="custom-mix-header">Create Custom Mix <a onClick={this.toggleCustomMixes}>{showMixControlsText}</a></h4>
<ReactCSSTransitionGroup transitionName="session-track-list" transitionAppear={true}>
{mixControls}
</ReactCSSTransitionGroup>
</div>`
>>>>>>> develop
else if @state.media.mediaSummary.backingTrackOpen
mediaType = "Audio File"
@ -348,11 +398,17 @@ mixins.push(Reflux.listenTo(JamTrackStore, 'onJamTrackChanged'))
else
mediaType = ""
if helpLink?
helpButton = `<a className="help-link button-grey" href={helpLink} onClick={this.help}>HELP</a>`
`<div className="media-controls-popup">
{header}
<MediaControls />
<MediaControls disabled={this.state.downloadingJamTrack || this.disableLoading}/>
{extraControls}
<a className="close-link button-orange" onClick={this.close}>{closeLinkText}</a>
<div className="actions">
{helpButton}
<a className="close-link button-orange" onClick={this.close}>{closeLinkText}</a>
</div>
</div>`
windowUnloaded: () ->
@ -436,7 +492,23 @@ mixins.push(Reflux.listenTo(JamTrackStore, 'onJamTrackChanged'))
return unless action?
if confirm(action)
JamTrackMixdownActions.enqueueMixdown(mixdown)
JamTrackMixdownActions.enqueueMixdown(mixdown, @enqueueDone)
enqueueDone: (enqueued) ->
@promptEstimate(enqueued)
promptEstimate: (enqueued) ->
time = enqueued.queue_time
if time == 0
alert("Your custom mix will take about 1 minute to be created.")
else
guess = Math.ceil(time / 60.0)
if guess == 1
msg = '1 minute'
else
msg = "#{guess} minutes"
alert("Your custom mix will take about #{msg} to be created.")
createMix: (e) ->
e.preventDefault()
@ -478,6 +550,8 @@ mixins.push(Reflux.listenTo(JamTrackStore, 'onJamTrackChanged'))
# automatically close the create custom mix area
@setState({creatingMixdown: false, showCustomMixes: false, showMyMixes: true})
@promptEstimate(created)
createMixdownFail: (jqXHR) ->
logger.debug("create mixdown fail (within PopupMediaControls)", jqXHR.status)
@setState({creatingMixdown: false})
@ -533,13 +607,12 @@ mixins.push(Reflux.listenTo(JamTrackStore, 'onJamTrackChanged'))
window.resizeTo(width, height + offset)
componentWillUpdate: (nextProps, nextState) ->
computeDisableLoading: (state) ->
@disableLoading = false
return unless nextState?
selectedMixdown = nextState?.jamTrackState?.jamTrack?.activeMixdown
selectedMixdown = state?.jamTrackState?.jamTrack?.activeMixdown
mixdownDownloading = false
if selectedMixdown?
@ -552,5 +625,10 @@ mixins.push(Reflux.listenTo(JamTrackStore, 'onJamTrackChanged'))
@disableLoading = SessionStore.downloadingJamTrack || mixdownDownloading
componentWillMount: () ->
@computeDisableLoading(@state)
componentWillUpdate: (nextProps, nextState) ->
@computeDisableLoading(nextState)
})

View File

@ -1,24 +1,40 @@
context = window
logger = context.JK.logger
NoVideoRecordActive = 0
WebCamRecordActive = 1
ScreenRecordActive = 2
mixins = []
# make sure this is actually us opening the window, not someone else (by checking for MixerStore)
# this check ensures we attempt to listen if this component is created in a popup
reactContext = if window.opener? then window.opener else window
accessOpener = false
if window.opener?
try
m = window.opener.MixerStore
accessOpener = true
catch e
reactContext = window
MixerStore = reactContext.MixerStore
RecordingStore = reactContext.RecordingStore
VideoStore = reactContext.VideoStore
if accessOpener
mixins.push(Reflux.listenTo(window.opener.RecordingStore,"onRecordingStateChanged"))
mixins.push(Reflux.listenTo(RecordingStore,"onRecordingStateChanged"))
# mixins.push(Reflux.listenTo(MixerStore,"onMixersChanged"))
@PopupRecordingStartStop = React.createClass({
mixins: mixins
#onMixersChanged: (mixers) ->
# this.setState(chatMixer: mixers.chatMixer)
onRecordingStateChanged: (recordingState) ->
this.setState(isRecording: recordingState.isRecording, recordedOnce: this.state.recordedOnce || recordingState.isRecording)
@ -26,13 +42,39 @@ if accessOpener
if this.state.isRecording
window.opener.RecordingActions.stopRecording()
else
window.opener.RecordingActions.startRecording()
recordChat = false
recordVideo = NoVideoRecordActive
$root = $(this.getDOMNode())
if @inputType != 'audio-only'
if $root.find('#recording-selection').val() == 'video-window'
recordVideo = ScreenRecordActive
else
recordVideo = WebCamRecordActive
recordChat = $root.find('#include-chat').is(':checked')
# if the video window isn't open, but a video option was selected...
if recordVideo != NoVideoRecordActive && !VideoStore.videoShared
logger.debug("prevent video from opening", VideoStore)
context.JK.prodBubble($root.find('.control'), 'video-window-not-open', {}, {positions:['bottom']})
return
logger.debug("@inputType, @udiotye", recordChat, recordVideo)
window.opener.RecordingActions.startRecording(recordVideo, recordChat)
onNoteShowHide: () ->
$root = $(this.getDOMNode())
audioVideoValue = $root.find('input[name="recording-input-type"]').val()
console.log("audio video value", audioVideoValue)
this.setState(showNote: !this.state.showNote)
getInitialState: () ->
{isRecording: window.ParentIsRecording, showNote: true, recordedOnce: false}
{isRecording: window.ParentIsRecording, showNote: true, recordedOnce: false, chatMixer: MixerStore.mixers?.chatMixer}
render: () ->
@ -53,16 +95,33 @@ if accessOpener
</div>
</div>`
recordingJSX = `<div className="recording-options">
<div className="field">
<input type="radio" name="recording-input-type" id="recording-input-both" defaultChecked="checked" />
<label htmlFor="recording-input-both">Record both video and audio</label>
<div className="clearall"></div>
chatHelp = `<a href="#" onClick={this.onChatHelp} className="chat-help">[?]</a>`
recordingJSX =
`<div className="recording-options">
<div className="video-settings">
<h3>Recording Type</h3>
<div className="field">
<input type="radio" name="recording-input-type" id="recording-input-audio" value="audio-only" defaultChecked="checked" />
<label htmlFor="recording-input-audio">Audio only</label>
<div className="clearall"></div>
</div>
<div className="field">
<input type="radio" name="recording-input-type" id="recording-input-both" value="audio-video" />
<label htmlFor="recording-input-both">Audio and video</label>
<div className="clearall"></div>
</div>
<div className="field">
<select className="easydropdown" name="recording-selection" id="recording-selection">
<option value="video-window">Record session video window</option>
<option value="webcam-only">Record my webcam only</option>
</select>
</div>
</div>
<div className="field">
<input type="radio" name="recording-input-type" id="recording-input-audio" />
<label htmlFor="recording-input-audio">Record audio only</label>
<div className="clearall"></div>
<div className="audio-settings">
<input type="checkbox" name="include-chat" id="include-chat" /><label htmlFor="include-chat">Include voice chat in recorded audio {chatHelp}</label>
</div>
</div>`
@ -108,6 +167,20 @@ if accessOpener
windowUnloaded: () ->
window.opener.RecordingActions.recordingControlsClosed()
onChatHelp: (e) ->
e.preventDefault()
context.JK.prodBubble($(e.target), 'vid-record-chat-input', {}, {positions:['left']})
trackInputType: (e) ->
$checkedType = $(e.target);
@inputType = $checkedType.val()
logger.debug("updated @inputType",e.target, @inputType)
trackAudioType: (e) ->
$checkedType = $(e.target);
@audioType = $checkedType.val()
logger.debug("updated @audioType", @inputType)
componentDidMount: () ->
$(window).unload(@windowUnloaded)
@ -116,6 +189,21 @@ if accessOpener
$recordingType = $root.find('input[type="radio"]')
context.JK.checkbox($recordingType)
@inputType = 'audio-only'
@audioType = 'audio-only'
$root.find('input[name="recording-input-type"]').on('ifChanged', @trackInputType)
$root.find('input[name="recording-input-chat-option"]').on('ifChanged', @trackAudioType)
$recordingRegion = $root.find('#recording-selection')
#console.log("$recordingou", $recordingRegion)
#context.JK.dropdown($recordingRegion)
$includeChat = $root.find('#include-chat')
context.JK.checkbox($includeChat)
@resizeWindow()
# this is necessary due to whatever the client's rendering behavior is.
@ -124,6 +212,9 @@ if accessOpener
componentDidUpdate: () ->
@resizeWindow()
$root = jQuery(this.getDOMNode())
$includeChat = $root.find('#include-chat')
resizeWindow: () =>
$container = $('#minimal-container')
width = $container.width()

View File

@ -15,6 +15,8 @@ ChannelGroupIds = context.JK.ChannelGroupIds
Reflux.listenTo(@JamTrackStore, "onJamTrackStateChanged")]
onJamTrackStateChanged: (jamTrackState) ->
@setState({jamTrackState: jamTrackState})
if jamTrackState.fullTrackActivated || jamTrackState.opened && jamTrackState.jamTrack.activeMixdown == null
@loadJamTrack(jamTrackState.jamTrack)
else if jamTrackState.closed
@ -29,6 +31,7 @@ ChannelGroupIds = context.JK.ChannelGroupIds
SessionActions.closeMedia(true)
#inputsChangedProcessed: (state) ->
@ -225,12 +228,12 @@ ChannelGroupIds = context.JK.ChannelGroupIds
contents = closeOptions
else if this.state.mediaSummary.mediaOpen
else if this.state.mediaSummary.mediaOpen || @state.jamTrackState?.jamTrack?
# give the users options to close it
if this.state.mediaSummary.recordingOpen
mediaType = "Recording"
else if this.state.mediaSummary.jamTrackOpen
else if this.state.mediaSummary.jamTrackOpen || @state.jamTrackState?.jamTrack?
mediaType = "JamTrack"
else if this.state.mediaSummary.backingTrackOpen
mediaType = "Audio File"
@ -308,7 +311,7 @@ ChannelGroupIds = context.JK.ChannelGroupIds
getInitialState:() ->
{mediaSummary:{mediaOpen: false}, isRecording: false, backingTracks: [], jamTracks: [], recordedTracks: [], metronome: null}
{mediaSummary:{mediaOpen: false}, isRecording: false, backingTracks: [], jamTracks: [], recordedTracks: [], metronome: null, jamTrackState: {}}
onAppInit: (app) ->
@app = app
@ -343,7 +346,7 @@ ChannelGroupIds = context.JK.ChannelGroupIds
@handlePopup()
handlePopup: () ->
if @state.mediaSummary.userNeedsMediaControls
if @state.mediaSummary.userNeedsMediaControls || @state.jamTrackState?.jamTrack?
unless @childWindow?
logger.debug("opening media control window")
@childWindow = window.open("/popups/media-controls", 'Media Controls', 'scrollbars=yes,toolbar=no,status=no,height=155,width=350')

View File

@ -68,6 +68,7 @@ SessionActions = @SessionActions
beforeDisconnect: () ->
@logger.debug("session beforeDisconnect")
return { freezeInteraction: true };
onAllowLeaveSession: () ->
@allowLeave = true

View File

@ -2,4 +2,5 @@ context = window
@AppActions = Reflux.createActions({
appInit: {}
openExternalUrl: {}
})

View File

@ -69,6 +69,7 @@ MIX_MODES = context.JK.MIX_MODES;
backingTracks = @session.backingTracks()
recordedJamTracks = @session.recordedJamTracks()
jamTracks = @session.jamTracks()
jamTrackMixdown = @session.jamTrackMixdown()
###
with mixer info, we use these to decide what kind of tracks are open in the backend
@ -92,6 +93,7 @@ MIX_MODES = context.JK.MIX_MODES;
@metronomeTrackMixers = []
@adhocTrackMixers = []
groupByType = (mixers, isLocalMixer) =>
for mixer in mixers
mediaType = mixer.media_type
@ -106,7 +108,10 @@ MIX_MODES = context.JK.MIX_MODES;
isJamTrack = false;
if jamTracks
if mixer.id == jamTrackMixdown.id
isJamTrack = true;
if !isJamTrack && jamTracks
# check if the ID matches that of an open jam track
for jamTrack in jamTracks
if mixer.id == jamTrack.id
@ -186,6 +191,8 @@ MIX_MODES = context.JK.MIX_MODES;
backingTrackOpen: @backingTracks.length > 0
metronomeOpen: @session.isMetronomeOpen()
# figure out if any media is open
mediaOpenSummary = false
for mediaType, mediaOpen of @mediaSummary
@ -352,6 +359,10 @@ MIX_MODES = context.JK.MIX_MODES;
else
logger.debug("MixerHelper: full jamtrack is active")
if jamTrackMixers.length == 1
logger.warn("ignoring wrong amount of mixers for JamTrack in Full Track mode")
return _jamTracks
for jamTrack in jamTracks
mixer = null
preMasteredClass = ""

View File

@ -8,5 +8,9 @@ logger = context.JK.logger
onAppInit: (app) ->
@trigger(app)
onOpenExternalUrl: (href) ->
context.JK.popExternalLink(href)
}
)

View File

@ -177,7 +177,9 @@ JamTrackActions = @JamTrackActions
, null, true)
when 'unknown'
if @jamTrack.activeMixdown.client_state != 'downloading'
# we need to check if @keyCheckTimeout exists; because if it does, we don't want to download while keying.
# 'unknown' is tricky here because the file probably is actually on disk, but the bridge API can say unknown until you've tried to key at least once
if @jamTrack.activeMixdown.client_state != 'downloading' && !@keyCheckTimeout?
@jamTrack.activeMixdown.client_state = 'downloading'
logger.debug("JamTrackStore: initiating download of mixdown")
context.jamClient.JamTrackDownload(@jamTrack.id, @jamTrack.activeMixdown.id, context.JK.currentUserId,
@ -501,6 +503,8 @@ JamTrackActions = @JamTrackActions
downloadFailureCallback: (errorMsg) ->
logger.debug("mixdown download failed", errorMsg);
if @jamTrack?.activeMixdown?
@jamTrack.activeMixdown.client_state = 'download_fail'
@reportError(@jamTrack.activeMixdown)

View File

@ -23,8 +23,15 @@ logger = context.JK.logger
@recordingModel = recordingModel
this.trigger({isRecording: @recordingModel.isRecording()})
onStartRecording: () ->
@recordingModel.startRecording()
onStartRecording: (recordVideo, recordChat) ->
frameRate = context.jamClient.GetCurrentVideoFrameRate() || 30;
NoVideoRecordActive = 0
WebCamRecordActive = 1
ScreenRecordActive = 2
logger.debug("onStartRecording: recordVideo: #{recordVideo}, recordChat: #{recordChat} frameRate: #{frameRate}")
@recordingModel.startRecording(recordVideo, recordChat, frameRate)
onStopRecording: () ->
@recordingModel.stopRecording()
@ -67,7 +74,7 @@ logger = context.JK.logger
popupRecordingControls: () ->
logger.debug("poupRecordingControls")
@recordingWindow = window.open("/popups/recording-controls", 'Recording', 'scrollbars=yes,toolbar=no,status=no,height=315,width=350')
@recordingWindow = window.open("/popups/recording-controls", 'Recording', 'scrollbars=yes,toolbar=no,status=no,height=315,width=340')
@recordingWindow.ParentRecordingStore = context.RecordingStore
@recordingWindow.ParentIsRecording = @recordingModel.isRecording()

View File

@ -79,7 +79,7 @@
return context.JK.dkeys(groupedTracks);
}
function startRecording() {
function startRecording(recordVideo, recordChat, recordFramerate) {
$self.triggerHandler('startingRecording', {});
@ -88,14 +88,15 @@
context.RecordingActions.startingRecording({isRecording: false})
currentRecording = rest.startRecording({"music_session_id": sessionId})
// 0 indicates the NoVideoRecordActive mode; so anything but that means video got recorded
currentRecording = rest.startRecording({"music_session_id": sessionId, record_video: recordVideo != 0})
.done(function(recording) {
currentRecordingId = recording.id;
currentOrLastRecordingId = recording.id;
// ask the backend to start the session.
var groupedTracks = groupTracksToClient(recording);
jamClient.StartRecording(recording["id"], groupedTracks, 0, false, 0);
jamClient.StartRecording(recording["id"], groupedTracks, recordVideo, recordChat, recordFramerate);
})
.fail(function(jqXHR) {
var details = { clientId: app.clientId, reason: 'rest', detail: arguments, isRecording: false }

View File

@ -53,5 +53,9 @@
.signed_in_to_google {
color: yellow;
}
.save-video {
margin-top:10px;
}
}

View File

@ -33,10 +33,21 @@ body.media-controls-popup.popup {
margin-bottom:5px;
}
.close-link {
.actions {
position:relative;
margin-top:20px;
font-size:11px;
margin-bottom:10px;
}
.help-link {
position:absolute;
left:-6px;
top:0;
}
.close-link {
}
.display-metronome {
@ -183,6 +194,10 @@ body.media-controls-popup.popup {
border-width:1px 0;
padding: 7px 0 20px;
&.not-active {
padding:7px 0 7px;
}
p {
line-height:125%;
color:$ColorTextTypical;
@ -222,4 +237,27 @@ body.media-controls-popup.popup {
}
}
}
.arrow-down {
float:none;
margin-left:5px;
margin-top:0;
margin-right:0;
border-top: 4px solid #fc0;
border-left: 4px solid transparent;
border-right: 4px solid transparent;
display:inline-block;
padding-top:1px;
}
.arrow-up {
float:none;
margin-right:0;
margin-left:5px;
margin-bottom:2px;
border-bottom: 4px solid #fc0;
border-left: 4px solid transparent;
border-right: 4px solid transparent;
display:inline-block;
padding-top:1px;
}
}

View File

@ -7,6 +7,8 @@
*= require client/ftue
*= require client/help
*= require icheck/minimal/minimal
*= require easydropdown
*= require easydropdown_jk
*= require_directory .
*= require client/metronomePlaybackModeSelect
*= require_directory ../client/react-components

View File

@ -10,12 +10,12 @@ body.recording-start-stop {
}
.recording-start-stop {
padding-left:44px;
padding-left:30px;
}
.control-holder {
width:100%;
margin: 1em 0;
margin: 10px 0 20px;
}
.helper {
@ -24,7 +24,20 @@ body.recording-start-stop {
vertical-align: middle;
}
.audio-settings {
margin-top:40px;
label {
display:inline;
margin-left:6px;
}
.icheckbox_minimal {
vertical-align:middle;
}
}
.control {
margin-left:20px;
width:231px;
height:34px;
@include border_box_sizing;
@ -38,7 +51,10 @@ body.recording-start-stop {
color:#ccc;
}
.chat-help {
text-decoration:none;
outline:0;
}
.control img {
vertical-align:middle;
margin-right:5px;
@ -59,12 +75,16 @@ body.recording-start-stop {
.field {
height:18px;
&:nth-child(1) {
&:nth-of-type(1) {
}
&:nth-child(2) {
&:nth-of-type(2) {
margin-top:9px;
}
&:nth-of-type(3) {
margin-top: 10px;
padding-left: 22px;
}
}
.note-show-hide {
@ -77,12 +97,22 @@ body.recording-start-stop {
}
.important-note {
margin-top:30px;
margin-top:15px;
line-height:150%;
font-size:12px;
width:260px;
}
h3 {
font-size:14px;
font-weight:bold;
margin-bottom:6px;
}
.video-settings {
margin-bottom:20px;
}
a.note-show-hide {
margin-top:5px;
text-decoration:underline;

View File

@ -114,6 +114,7 @@ class ApiJamTrackMixdownsController < ApiController
enqueued = @package.enqueue_if_needed
log.debug("jamtrack mixdown #{enqueued ? "ENQUEUED" : "NOT ENQUEUED"}: mixdown_package=#{@package.id} ")
@queue_time = enqueued ? enqueued : 0
return
else
render :json => { :message => "download limit surpassed", :errors=>@package.errors }, :status => 403

View File

@ -83,7 +83,7 @@ class ApiRecordingsController < ApiController
raise JamPermissionError, ValidationMessages::PERMISSION_VALIDATION_ERROR unless music_session.users.exists?(current_user)
@recording = Recording.start(music_session, current_user)
@recording = Recording.start(music_session, current_user, record_video: params[:record_video])
if @recording.errors.any?
response.status = :unprocessable_entity

View File

@ -7,7 +7,7 @@ class ApiSearchController < ApiController
def index
if 1 == params[Search::PARAM_MUSICIAN].to_i || 1 == params[Search::PARAM_BAND].to_i
query = parasobj.clone
query = params.clone
query[:remote_ip] = request.remote_ip
if 1 == query[Search::PARAM_MUSICIAN].to_i
@search = Search.musician_filter(query, current_user)

Some files were not shown because too many files have changed in this diff Show More