* VRFS-2876 - pro licensing added and 20 second snippet
This commit is contained in:
parent
882f2267cf
commit
9279d88d8d
|
|
@ -6,22 +6,25 @@
|
|||
= f.input :plan_code, :label=>'Recurly Plan Code', :required=>true, :hint => 'Must match plan code in Recurly'
|
||||
= f.input :version, :label => 'Version', :hint => 'Increment this value whenever you invalidate (update) the media in the JamTrack. Changing JMEP does not count as a version change; changing anything about a track (audio, instrument, part) does.'
|
||||
//= f.input :initial_play_silence, :label => 'Initial Play Silence (seconds)'
|
||||
= f.input :time_signature, collection: JamRuby::JamTrack::TIME_SIGNATURES, include_blank: false
|
||||
= f.input :time_signature, collection: JamRuby::JamTrack::TIME_SIGNATURES, include_blank: true
|
||||
= f.input :status, collection: JamRuby::JamTrack::STATUS, include_blank: false, hint: 'Only set to Production when end users should be able to purchase this JamTrack'
|
||||
= f.input :recording_type, collection: JamRuby::JamTrack::RECORDING_TYPE, include_blank: false
|
||||
= f.input :original_artist, :input_html => { :rows=>1, :maxlength=>1000 }
|
||||
= f.input :songwriter, :input_html => { :rows=>1, :maxlength=>1000 }
|
||||
= f.input :publisher, :input_html => { :rows=>1, :maxlength=>1000 }
|
||||
= f.input :licensor, collection: JamRuby::JamTrackLicensor.all, include_blank: false
|
||||
= f.input :pro, collection: JamRuby::JamTrack::PRO, include_blank: false
|
||||
= f.input :licensor, collection: JamRuby::JamTrackLicensor.all, include_blank: true
|
||||
= f.input :genre, collection: JamRuby::Genre.all, include_blank: false
|
||||
= f.input :sales_region, collection: JamRuby::JamTrack::SALES_REGION, include_blank: false
|
||||
= f.input :price, :required=>true, :input_html=>{type:'numeric'}
|
||||
= f.input :price, :required => true, :input_html => {type: 'numeric'}
|
||||
= f.input :pro_ascap, :label => 'ASCAP royalties due?'
|
||||
= f.input :pro_bmi, :label => 'BMI royalties due?'
|
||||
= f.input :pro_sesac, :label => 'SESAC royalties due?'
|
||||
= f.input :reproduction_royalty, :label => 'Reproduction Royalty'
|
||||
= f.input :public_performance_royalty, :label => 'Public Performance Royalty'
|
||||
= f.input :reproduction_royalty_amount, :required=>true, :input_html=>{type:'numeric'}
|
||||
= f.input :licensor_royalty_amount, :required=>true, :input_html=>{type:'numeric'}
|
||||
= f.input :pro_royalty_amount, :required=>true, :input_html=>{type:'numeric'}
|
||||
= f.input :preview_start_time_raw, :label=>'Preview Start Time', :hint => 'MM:SS:MLS', :as => :string
|
||||
|
||||
//= f.input :url, :as => :file, :label => 'Audio File'
|
||||
= f.input :jmep_text, :as => :text, :label => "JMEP Text", :input_html => {:rows => 5 }, :hint => 'Tap-Ins & Lead Silence. Examples: https://jamkazam.atlassian.net/wiki/pages/viewpage.action?pageId=39289025#JamKazamMeta-EventProcessor(JMEP)-CommonExamples'
|
||||
= f.input :jmep_json, :as => :text, :label => "JMEP Json", :input_html => {:rows => 5, :readonly => true }, :hint => 'Readonly field. This is shown here just so you can see what your JMEP got converted to readily'
|
||||
|
|
|
|||
|
|
@ -2,8 +2,11 @@ class JamRuby::JamTrack
|
|||
|
||||
# add a custom validation
|
||||
|
||||
attr_accessor :preview_generate_error
|
||||
|
||||
before_save :jmep_json_generate
|
||||
validate :jmep_text_validate
|
||||
validate :preview
|
||||
|
||||
def jmep_text_validate
|
||||
begin
|
||||
|
|
@ -14,6 +17,11 @@ class JamRuby::JamTrack
|
|||
end
|
||||
|
||||
def jmep_json_generate
|
||||
self.genre_id = nil if self.genre_id == ''
|
||||
self.licensor_id = nil if self.licensor_id == ''
|
||||
self.jmep_json = nil if self.jmep_json == ''
|
||||
self.time_signature = nil if self.time_signature == ''
|
||||
|
||||
begin
|
||||
self[:jmep_json] = JmepManager.execute(self.jmep_text)
|
||||
rescue ArgumentError => err
|
||||
|
|
@ -21,5 +29,96 @@ class JamRuby::JamTrack
|
|||
end
|
||||
end
|
||||
|
||||
def preview
|
||||
if preview_generate_error
|
||||
errors.add(:preview_url, preview_generate_error)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
# this is used by active admin/jam-admin
|
||||
def preview_start_time_raw
|
||||
if self.preview_start_time.nil? || self.preview_start_time.nil?
|
||||
''
|
||||
else
|
||||
seconds = self.preview_start_time.to_f/1000
|
||||
time = Time.at(seconds)
|
||||
time.strftime("%M:%S:#{(self.preview_start_time % 1000).to_s.rjust(3, '0')}")
|
||||
end
|
||||
end
|
||||
|
||||
# this is used by active admin/jam-admin
|
||||
def preview_start_time_raw=(new_value)
|
||||
|
||||
value = nil
|
||||
if new_value == nil || new_value == ''
|
||||
value = nil
|
||||
else
|
||||
if new_value && new_value.kind_of?(String) && new_value.include?(':')
|
||||
bits = new_value.split(':')
|
||||
if bits.length != 3
|
||||
raise "format of preview start time must be MM:SS:MLS"
|
||||
end
|
||||
|
||||
value = (bits[0].to_i * 60000) + (bits[1].to_i * 1000) + (bits[2].to_i)
|
||||
|
||||
else
|
||||
raise "format of preview start time must be MM:SS:MLS"
|
||||
end
|
||||
end
|
||||
|
||||
if !value.nil? && value != self.preview_start_time
|
||||
self.preview_start_time = value
|
||||
generate_preview
|
||||
else
|
||||
self.preview_start_time = value
|
||||
end
|
||||
end
|
||||
|
||||
def generate_preview
|
||||
|
||||
begin
|
||||
Dir.mktmpdir do |tmp_dir|
|
||||
|
||||
input = File.join(tmp_dir, 'in.ogg')
|
||||
output = File.join(tmp_dir, 'out.ogg')
|
||||
|
||||
start = self.preview_start_time.to_f / 1000
|
||||
stop = start + 20
|
||||
|
||||
master_track = self.master_track
|
||||
|
||||
raise 'no master track' unless master_track
|
||||
|
||||
s3_manager.download(master_track.url_by_sample_rate(44), input)
|
||||
|
||||
command = "sox \"#{input}\" \"#{output}\" trim #{start} #{stop}"
|
||||
|
||||
@@log.debug("trimming using: " + command)
|
||||
|
||||
sox_output = `#{command}`
|
||||
|
||||
result_code = $?.to_i
|
||||
|
||||
if result_code != 0
|
||||
@preview_generate_error = "unable to execute cut command #{sox_output}"
|
||||
else
|
||||
@@log.debug("uploading preview to #{self.preview_filename}")
|
||||
|
||||
s3_manager.upload(self.preview_filename, output)
|
||||
|
||||
# and finally update the JamTrackTrack with the new info
|
||||
self["preview_url"] = self.preview_filename
|
||||
self["preview_md5"] = ::Digest::MD5.file(output).hexdigest
|
||||
self["preview_length"] = File.new(output).size
|
||||
self.save!
|
||||
end
|
||||
end
|
||||
rescue Exception => e
|
||||
@preview_generate_error = e.to_s
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -258,4 +258,5 @@ jam_track_version.sql
|
|||
recorded_jam_track_tracks.sql
|
||||
jam_track_jmep_data.sql
|
||||
add_jam_track_bitrates.sql
|
||||
jam_track_importer.sql
|
||||
jam_track_importer.sql
|
||||
jam_track_pro_licensing_update.sql
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
ALTER TABLE jam_tracks ADD COLUMN pro_ascap BOOLEAN DEFAULT FALSE NOT NULL;
|
||||
ALTER TABLE jam_tracks ADD COLUMN pro_bmi BOOLEAN DEFAULT FALSE NOT NULL;
|
||||
ALTER TABLE jam_tracks ADD COLUMN pro_sesac BOOLEAN DEFAULT FALSE NOT NULL;
|
||||
UPDATE jam_tracks SET pro_ascap = TRUE WHERE pro = 'ASCAP';
|
||||
UPDATE jam_tracks SET pro_bmi = TRUE WHERE pro = 'BMI';
|
||||
UPDATE jam_tracks SET pro_sesac = TRUE WHERE pro = 'SESAC';
|
||||
ALTER TABLE jam_tracks DROP COLUMN pro;
|
||||
ALTER TABLE jam_tracks DROP Column pro_royalty_amount;
|
||||
ALTER TABLE jam_tracks ADD COLUMN preview_start_time INTEGER;
|
||||
ALTER TABLE jam_tracks RENAME COLUMN url TO preview_url;
|
||||
ALTER TABLE jam_tracks RENAME COLUMN md5 TO preview_md5;
|
||||
ALTER TABLE jam_tracks RENAME COLUMN length TO preview_length;
|
||||
|
|
@ -11,7 +11,7 @@ class JamTrackUploader < CarrierWave::Uploader::Base
|
|||
|
||||
# Add a white list of extensions which are allowed to be uploaded.
|
||||
def extension_white_list
|
||||
%w(jkz)
|
||||
%w(ogg)
|
||||
end
|
||||
|
||||
def store_dir
|
||||
|
|
@ -23,6 +23,6 @@ class JamTrackUploader < CarrierWave::Uploader::Base
|
|||
end
|
||||
|
||||
def filename
|
||||
"#{model.store_dir}/#{model.filename}" if model.id
|
||||
"#{model.preview_filename}" if model.id && model.uploading_preview
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -102,7 +102,6 @@ module JamRuby
|
|||
jam_track.price = 1.99
|
||||
jam_track.reproduction_royalty_amount = 0
|
||||
jam_track.licensor_royalty_amount = 0
|
||||
jam_track.pro_royalty_amount = 0
|
||||
jam_track.sales_region = 'United States'
|
||||
jam_track.recording_type = 'Cover'
|
||||
jam_track.description = "This is a JamTrack audio file for use exclusively with the JamKazam service. This JamTrack is a high quality cover of the #{jam_track.original_artist} song \"#{jam_track.name}\"."
|
||||
|
|
|
|||
|
|
@ -12,35 +12,37 @@ module JamRuby
|
|||
|
||||
@@log = Logging.logger[JamTrack]
|
||||
|
||||
mount_uploader :url, JamTrackUploader
|
||||
mount_uploader :preview_url, JamTrackUploader
|
||||
|
||||
attr_accessor :uploading_preview
|
||||
attr_accessible :name, :description, :bpm, :time_signature, :status, :recording_type,
|
||||
:original_artist, :songwriter, :publisher, :licensor, :licensor_id, :pro, :genre, :genre_id, :sales_region, :price,
|
||||
:reproduction_royalty, :public_performance_royalty, :reproduction_royalty_amount,
|
||||
:licensor_royalty_amount, :pro_royalty_amount, :plan_code, :initial_play_silence, :jam_track_tracks_attributes,
|
||||
:jam_track_tap_ins_attributes, :version, :jmep_json, :jmep_text, as: :admin
|
||||
:jam_track_tap_ins_attributes, :version, :jmep_json, :jmep_text, :pro_ascap, :pro_bmi, :pro_sesac, :preview_start_time_raw, as: :admin
|
||||
|
||||
validates :name, presence: true, uniqueness: true, length: {maximum: 200}
|
||||
validates :plan_code, presence: true, uniqueness: true, length: {maximum: 50 }
|
||||
validates :description, length: {maximum: 1000}
|
||||
validates :time_signature, inclusion: {in: [nil] + TIME_SIGNATURES}
|
||||
validates :time_signature, inclusion: {in: [nil] + [''] + TIME_SIGNATURES} # the empty string is needed because of activeadmin
|
||||
validates :status, inclusion: {in: [nil] + STATUS}
|
||||
validates :recording_type, inclusion: {in: [nil] + RECORDING_TYPE}
|
||||
validates :original_artist, length: {maximum: 200}
|
||||
validates :songwriter, length: {maximum: 1000}
|
||||
validates :publisher, length: {maximum: 1000}
|
||||
validates :pro, inclusion: {in: [nil] + PRO}
|
||||
validates :sales_region, inclusion: {in: [nil] + SALES_REGION}
|
||||
validates_format_of :price, with: /^\d+\.*\d{0,2}$/
|
||||
validates :version, presence: true
|
||||
|
||||
validates :preview_start_time, numericality: {only_integer: true}, length: {in: 1..1000}, :allow_nil => true
|
||||
validates :pro_ascap, inclusion: {in: [true, false]}
|
||||
validates :pro_bmi, inclusion: {in: [true, false]}
|
||||
validates :pro_sesac, inclusion: {in: [true, false]}
|
||||
validates :public_performance_royalty, inclusion: {in: [nil, true, false]}
|
||||
validates :reproduction_royalty, inclusion: {in: [nil, true, false]}
|
||||
validates :public_performance_royalty, inclusion: {in: [nil, true, false]}
|
||||
|
||||
validates_format_of :reproduction_royalty_amount, with: /^\d+\.*\d{0,3}$/
|
||||
validates_format_of :licensor_royalty_amount, with: /^\d+\.*\d{0,3}$/
|
||||
validates_format_of :pro_royalty_amount, with: /^\d+\.*\d{0,3}$/
|
||||
|
||||
before_save :sanitize_active_admin
|
||||
|
||||
belongs_to :genre, class_name: "JamRuby::Genre"
|
||||
belongs_to :licensor , class_name: 'JamRuby::JamTrackLicensor', foreign_key: 'licensor_id'
|
||||
|
|
@ -91,15 +93,10 @@ module JamRuby
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
# create storage directory that will house this jam_track, as well as
|
||||
def store_dir
|
||||
"jam_tracks/#{id}"
|
||||
end
|
||||
|
||||
# create name of the file
|
||||
def filename
|
||||
"#{name}.jkz"
|
||||
def preview_filename
|
||||
"jam_track_previews/#{self.original_artist}/#{self.name}/preview-44100.ogg"
|
||||
end
|
||||
|
||||
# creates a short-lived URL that has access to the object.
|
||||
|
|
@ -107,9 +104,12 @@ module JamRuby
|
|||
# we would verify their rights (can_download?), and generates a URL in response to the click so that they can download
|
||||
# but the url is short lived enough so that it wouldn't be easily shared
|
||||
def sign_url(expiration_time = 120)
|
||||
s3_manager.sign_url(self[:url], {:expires => expiration_time, :response_content_type => 'audio/jkz', :secure => false})
|
||||
s3_manager.sign_url(self[:preview_url], {:expires => expiration_time, :response_content_type => 'audio/ogg', :secure => false})
|
||||
end
|
||||
|
||||
def master_track
|
||||
JamTrackTrack.where(jam_track_id: self.id).where(track_type: 'Master').first
|
||||
end
|
||||
|
||||
def can_download?(user)
|
||||
owners.include?(user)
|
||||
|
|
@ -118,50 +118,5 @@ module JamRuby
|
|||
def right_for_user(user)
|
||||
jam_track_rights.where("user_id=?", user).first
|
||||
end
|
||||
|
||||
def self.list_downloads(user, limit = 100, since = 0, bitrate = 48)
|
||||
since = 0 unless since || since == '' # guard against nil
|
||||
downloads = []
|
||||
|
||||
user.jam_track_rights
|
||||
.limit(limit)
|
||||
.where('jam_track_rights.id > ?', since)
|
||||
.each do |jam_track_right|
|
||||
download = {
|
||||
:type => "jam_track",
|
||||
:id => jam_track_right.id.to_s,
|
||||
:jam_track_id => jam_track_right.jam_track_id,
|
||||
:created_at => jam_track_right.created_at,
|
||||
:next => jam_track_right.id
|
||||
}
|
||||
if(bitrate==48)
|
||||
download[:length] = jam_track_right.length_48
|
||||
download[:md5] = jam_track_right.md5_48
|
||||
download[:url] = jam_track_right.url_48
|
||||
else
|
||||
download[:length] = jam_track_right.length_44
|
||||
download[:md5] = jam_track_right.md5_44
|
||||
download[:url] = jam_track_right.url_44
|
||||
end
|
||||
downloads << download
|
||||
end
|
||||
|
||||
next_id = downloads[-1][:next] if downloads.length > 0
|
||||
next_id = since if next_id.nil? # echo back to the client the same value they passed in, if there are no results
|
||||
|
||||
{
|
||||
'downloads' => downloads,
|
||||
'next' => next_id.to_s
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
def sanitize_active_admin
|
||||
self.genre_id = nil if self.genre_id == ''
|
||||
self.licensor_id = nil if self.licensor_id == ''
|
||||
self.jmep_json = nil if self.jmep_json = ''
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -35,7 +35,6 @@ module JamRuby
|
|||
else
|
||||
raise "format of offset time must be MM:SS:MLS"
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -730,14 +730,12 @@ FactoryGirl.define do
|
|||
sequence(:original_artist) { |n| "original-artist-#{n}" }
|
||||
sequence(:songwriter) { |n| "songwriter-#{n}" }
|
||||
sequence(:publisher) { |n| "publisher-#{n}" }
|
||||
pro 'ASCAP'
|
||||
sales_region 'United States'
|
||||
price 1.99
|
||||
reproduction_royalty true
|
||||
public_performance_royalty true
|
||||
reproduction_royalty_amount 0.999
|
||||
licensor_royalty_amount 0.999
|
||||
pro_royalty_amount 0.999
|
||||
sequence(:plan_code) { |n| "jamtrack-#{n}" }
|
||||
|
||||
genre JamRuby::Genre.first
|
||||
|
|
|
|||
|
|
@ -57,7 +57,6 @@ describe JamTrackImporter do
|
|||
jam_track.original_artist.should eq('Artist 1')
|
||||
jam_track.songwriter.should be_nil
|
||||
jam_track.publisher.should be_nil
|
||||
jam_track.pro.should be_nil
|
||||
jam_track.sales_region.should eq('United States')
|
||||
jam_track.price.should eq(1.99)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -17,14 +17,6 @@ describe JamTrackRight do
|
|||
|
||||
end
|
||||
|
||||
it "lists" do
|
||||
jam_track_right = FactoryGirl.create(:jam_track_right)
|
||||
jam_tracks = JamTrack.list_downloads(jam_track_right.user)
|
||||
jam_tracks.should have_key('downloads')
|
||||
jam_tracks.should have_key('next')
|
||||
jam_tracks['downloads'].should have(1).items
|
||||
end
|
||||
|
||||
describe "validations" do
|
||||
it "one purchase per user/jam_track combo" do
|
||||
user = FactoryGirl.create(:user)
|
||||
|
|
|
|||
|
|
@ -119,9 +119,9 @@ describe JamTrack do
|
|||
end
|
||||
|
||||
describe "upload/download" do
|
||||
JKA_NAME = 'blah.jkz'
|
||||
PREVIEW_NAME = 'blah.ogg'
|
||||
|
||||
in_directory_with_file(JKA_NAME)
|
||||
in_directory_with_file(PREVIEW_NAME)
|
||||
|
||||
before(:all) do
|
||||
original_storage = JamTrackUploader.storage = :fog
|
||||
|
|
@ -137,17 +137,17 @@ describe JamTrack do
|
|||
|
||||
it "uploads to s3 with correct name, and then downloads via signed URL" do
|
||||
jam_track = FactoryGirl.create(:jam_track)
|
||||
uploader = JamTrackUploader.new(jam_track, :url)
|
||||
uploader.store!(File.open(JKA_NAME)) # uploads file
|
||||
uploader = JamTrackUploader.new(jam_track, :preview_url)
|
||||
uploader.store!(File.open(PREVIEW_NAME)) # uploads file
|
||||
jam_track.save!
|
||||
|
||||
# verify that the uploader stores the correct path
|
||||
jam_track[:url].should == jam_track.store_dir + '/' + jam_track.filename
|
||||
jam_track[:preview_url].should == jam_track.preview_filename
|
||||
|
||||
# verify it's on S3
|
||||
s3 = S3Manager.new(APP_CONFIG.aws_bucket, APP_CONFIG.aws_access_key_id, APP_CONFIG.aws_secret_access_key)
|
||||
s3.exists?(jam_track[:url]).should be_true
|
||||
s3.length(jam_track[:url]).should == 'abc'.length
|
||||
s3.exists?(jam_track[:preview_url]).should be_true
|
||||
s3.length(jam_track[:preview_url]).should == 'abc'.length
|
||||
|
||||
# download it via signed URL, and check contents
|
||||
url = jam_track.sign_url
|
||||
|
|
|
|||
|
|
@ -23,15 +23,6 @@ class ApiJamTracksController < ApiController
|
|||
render "api_jam_tracks/purchased", :layout => nil
|
||||
end
|
||||
|
||||
def downloads
|
||||
sample_rate = params[:sample_rate].nil? ? nil : params[:sample_rate].to_i
|
||||
begin
|
||||
render :json => JamTrack.list_downloads(current_user, params[:limit], params[:since], sample_rate), :status => 200
|
||||
rescue
|
||||
render :json => { :message => "could not produce list of files" }, :status => 403
|
||||
end
|
||||
end
|
||||
|
||||
def download
|
||||
if @jam_track_right.valid?
|
||||
sample_rate = params[:sample_rate].nil? ? nil : params[:sample_rate].to_i
|
||||
|
|
|
|||
|
|
@ -206,7 +206,6 @@ SampleApp::Application.routes.draw do
|
|||
# Jamtracks
|
||||
match '/jamtracks' => 'api_jam_tracks#index', :via => :get, :as => 'api_jam_tracks_list'
|
||||
match '/jamtracks/purchased' => 'api_jam_tracks#purchased', :via => :get, :as => 'api_jam_tracks_purchased'
|
||||
match '/jamtracks/downloads' => 'api_jam_tracks#downloads', :via => :get, :as => 'api_jam_tracks_downloads'
|
||||
match '/jamtracks/download/:id' => 'api_jam_tracks#download', :via => :get, :as => 'api_jam_tracks_download'
|
||||
match '/jamtracks/enqueue/:id' => 'api_jam_tracks#enqueue', :via => :post, :as => 'api_jam_tracks_enqueue'
|
||||
match '/jamtracks/rights/:id' => 'api_jam_tracks#show_jam_track_right', :via => :get, :as => 'api_jam_tracks_show_right'
|
||||
|
|
|
|||
|
|
@ -717,14 +717,12 @@ FactoryGirl.define do
|
|||
sequence(:original_artist) { |n| "original-artist-#{n}" }
|
||||
sequence(:songwriter) { |n| "songwriter-#{n}" }
|
||||
sequence(:publisher) { |n| "publisher-#{n}" }
|
||||
pro 'ASCAP'
|
||||
sales_region 'United States'
|
||||
price 1.99
|
||||
reproduction_royalty true
|
||||
public_performance_royalty true
|
||||
reproduction_royalty_amount 0.999
|
||||
licensor_royalty_amount 0.999
|
||||
pro_royalty_amount 0.999
|
||||
sequence(:plan_code) { |n| "jamtrack-#{n}" }
|
||||
ignore do
|
||||
make_track true
|
||||
|
|
|
|||
Loading…
Reference in New Issue