Mute or unmute any tracks 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.
`
seeAllByArtist: (e) ->
e.preventDefault()
jamTrack = @state.jamTrackState?.jamTrack
console.log("seeAllByArtist context", jamTrack)
window.open('/client?artist=' + encodeURIComponent(jamTrack.original_artist) + '#/jamtrack/search')
windowUnloaded: () ->
JamTrackPlayerActions.windowUnloaded() unless window.DontAutoCloseMedia
toggleMyMixes: (e) ->
e.preventDefault()
@setState({showMyMixes: !@state.showMyMixes})
toggleCustomMixes: (e) ->
e.preventDefault()
@setState({showCustomMixes: !@state.showCustomMixes})
downloadNotReady: (mixdown, e) ->
alert("This mix is not yet ready to download.")
e.preventDefault()
verificationCheck: () ->
if @state.user?.email_needs_verification
alert("Check your email and click the verification link. Refresh this page when done, and try again.")
return @state.user?.email_needs_verification
downloadMixdownReady: (mixdown, e) ->
if @verificationCheck()
e.preventDefault()
return
if mixdown.myPackage?.signing_state == 'SIGNED'
if /iPhone|iPad|iPod/i.test(navigator.userAgent)
# fall through
else
e.preventDefault()
new window.Fingerprint2().get((result, components) => (
iframe = document.createElement("iframe")
iframe.src = @downloadMixdownUrl(mixdown, result)
iframe.style.display = "none"
document.body.appendChild(iframe);
))
else
alert("The mix is not yet ready to download")
downloadMixdownUrl: (mixdown, result) ->
window.location.protocol + '//' + window.location.host + "/api/mixdowns/#{mixdown.id}/download.mp3?file_type=mp3&sample_rate=48&download=1&mark=#{result}"
activateStem: (e) ->
e.preventDefault()
return if @verificationCheck()
$select = $(this.getDOMNode()).find('.active-stem-select')
selectedTrackId = $select.val()
if !selectedTrackId? || selectedTrackId == ''
alert("You must pick a track from the dropdown in order to play it.")
else
@setState({editingMixdownId: null})
e.preventDefault()
if @disableLoading
alert('Certain actions are disabled while a track is being loaded.')
return
# make this package the active one
JamTrackPlayerActions.openStem(selectedTrackId)
addUpgradeToCart: (jamtrack) ->
console.log("adding upgrade to cart")
params = {id: jamtrack.id, variant: 'download'}
rest.addJamtrackToShoppingCart(params).done((response) =>
console.log("added item to shopping cart. fast_redeem? " + response.fast_redeem)
if response.fast_reedem
if context.JK.currentUserId?
window.open('/client#/redeemComplete')
else
window.open('/client#/redeemSignup')
else
window.open('/client#/shoppingCart')
).fail(((jqxhr) =>
handled = false
if jqxhr.status == 422
body = JSON.parse(jqxhr.responseText)
if body.errors?.cart_id?[0] == 'has already been taken'
console.log("already taken, just show shopping cart")
window.open('/client#/shoppingCart')
return
else if body.errors && body.errors.base
handled = true
alert("You can not have a mix of free and non-free items in your shopping cart.\n\nIf you want to add this new item to your shopping cart, then clear out all current items by clicking on the shopping cart icon and clicking 'delete' next to each item.")
if !handled
alert("Error adding to shoppig cart. " + jqxhr.responseText)
))
downloadStem: (e) ->
if @verificationCheck()
e.preventDefault()
return
$select = $(this.getDOMNode()).find('.active-stem-select')
selectedTrackId = $select.val()
if !@state.jamTrackState.jamTrack.can_download
e.preventDefault()
if confirm("You have not purchased the rights to download a JamTrack. Add them to your shopping cart?")
@addUpgradeToCart(@state.jamTrackState.jamTrack)
return
if !selectedTrackId? || selectedTrackId == ''
e.preventDefault()
alert("You must select a track in order to download and also click the folder icon.")
else
if /iPhone|iPad|iPod/i.test(navigator.userAgent)
if @state.jamTrackState.jamTrack?.last_stem_id
# fall through
else
e.preventDefault()
alert("You must select a track in order to download and also click the folder icon.")
else
e.preventDefault()
try
new window.Fingerprint2().get((result, components) => (
iframe = document.createElement("iframe")
iframe.src = @createStemUrl(@state.jamTrackState.jamTrack.id, selectedTrackId, result)
iframe.style.display = "none"
document.body.appendChild(iframe);
))
catch error
logger.error("not working: ", error)
alert("Unable to download. Please try a different browser.")
createStemUrl: (jamTrackId, stemId, result) ->
window.location.protocol + '//' + window.location.host + "/api/jamtracks/#{jamTrackId}/stems/#{stemId}/download.mp3?file_type=mp3&download=1&mark=#{result}"
stemChanged: () ->
mixdownPlay: (mixdown, e) ->
@setState({editingMixdownId: null})
e.preventDefault()
if @disableLoading
alert('Certain actions are disabled while a track is being loaded.')
return
# make this package the active one
JamTrackPlayerActions.openMixdown(mixdown)
jamTrackPlay: (jamtrack, e) ->
e.preventDefault()
# user wants to select the full track
if @disableLoading
alert('Certain actions are disabled while a track is being loaded.')
return
JamTrackPlayerActions.activateNoMixdown(jamtrack)
jamTrackDownload: (jamTrack, e) ->
if @verificationCheck()
e.preventDefault()
return
if !@state.jamTrackState.jamTrack.can_download
e.preventDefault()
if confirm("You have not purchased the rights to download a JamTrack. Add them to your shopping cart?")
@addUpgradeToCart(@state.jamTrackState.jamTrack)
return
if /iPhone|iPad|iPod/i.test(navigator.userAgent)
# fall through
else
e.preventDefault()
new window.Fingerprint2().get((result, components) => (
iframe = document.createElement("iframe")
iframe.src = @createJamTrackUrl(jamTrack, result)
iframe.style.display = "none"
document.body.appendChild(iframe);
))
createJamTrackUrl: (jamTrack, result) ->
window.location.protocol + '//' + window.location.host + "/api/jamtracks/#{jamTrack.id}/stems/master/download.mp3?file_type=mp3&download=1&mark=#{result}"
onEditKeydown: (mixdown, e) ->
logger.debug("on edit keydown", e)
if e.keyCode == 13 # enter
@mixdownSave(mixdown, e)
else if e.keyCode == 27 # esc
@setState({editingMixdownId: null})
mixdownEdit: (mixdown) ->
@setState({editingMixdownId: mixdown.id})
mixdownSave: (mixdown, e) ->
e.preventDefault()
$input = $(this.getDOMNode()).find('input.edit-name')
newValue = $input.val()
logger.debug("editing mixdown name to be: " + newValue)
JamTrackPlayerActions.editMixdown({id: mixdown.id, name: newValue})
@setState({editingMixdownId: null})
mixdownDelete: (mixdown) ->
if @state.editingMixdownId?
@setState({editingMixdownId: null})
return
if confirm("Delete this custom mix?")
JamTrackPlayerActions.deleteMixdown(mixdown)
mixdownError: (mixdown) ->
myPackage = mixdown.myPackage
if myPackage?
switch myPackage.signing_state
when 'QUIET_TIMEOUT'
action = 'Custom mix never got created. Retry?'
when 'QUEUED_TIMEOUT'
action = 'Custom mix was never built. Retry?'
when 'SIGNING_TIMEOUT'
action = 'Custom mix took took long to build. Retry?'
when 'ERROR'
action = 'Custom mix failed to build. Retry?'
else
action = 'Custom mix never got created. Retry?'
return unless action?
if confirm(action)
JamTrackPlayerActions.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()
return if @state.creatingMix
$root = $(@getDOMNode())
name = $root.find('input[name="mix-name"]').val()
speed = $root.find('select[name="mix-speed"]').val()
pitch = $root.find('select[name="mix-pitch"]').val()
if name == null || name == ''
@setState({createMixdownErrors: {errors: {'Mix Name': ["can't be blank"]}}})
return
# sanitize junk out of speed/pitch
if speed == '' || speed.indexOf('separator') > -1
speed = undefined
else
speed = parseInt(speed)
if pitch == '' || pitch.indexOf('separator') > -1
pitch = undefined
else
pitch = parseInt(pitch)
count_in = false
# get mute state of all tracks
$mutes = $(@getDOMNode()).find('.stems .stem .stem-mute')
tracks = []
$mutes.each((i, mute) =>
$mute = $(mute)
stemId = $mute.attr('data-stem-id')
muted = $mute.is(':checked')
if stemId == 'count-in'
count_in = !muted
else
tracks.push({id: stemId, mute: muted})
)
mixdown = {
jamTrackID: @state.jamTrackState.jamTrack.id,
name: name,
settings: {speed: speed, pitch: pitch, "count-in": count_in, tracks: tracks}
}
JamTrackPlayerActions.createMixdown(mixdown, @createMixdownDone, @createMixdownFail)
@setState({creatingMixdown: true, createMixdownErrors: null})
createMixdownDone: (created) ->
logger.debug("created (within PopupMediaControls)", created)
@setState({creatingMixdown: false, showCustomMixes: true, showMyMixes: true})
@promptEstimate(created)
createMixdownFail: (jqXHR) ->
logger.debug("create mixdown fail (within PopupMediaControls)", jqXHR.status)
@setState({creatingMixdown: false})
if jqXHR.status == 422
response = JSON.parse(jqXHR.responseText)
logger.warn("failed to create mixdown", response, jqXHR.responseText)
@setState({createMixdownErrors: response})
fetchJamTrackInfo: () ->
rest.getJamTrack({plan_code: gon.jamtrack_id})
.done((response) =>
JamTrackPlayerActions.open(response, false);
@fetchUserInfo()
)
.fail((jqXHR) =>
alert("Unable to fetch JamTrack information. Try logging in.")
)
fetchUserInfo: () ->
rest.getUserDetail()
.done((response) =>
rest.postUserEvent({name: 'jamtrack_web_player_open'})
context.stats.write('web.jamtrack_web_player.open', {
value: 1,
user_id: context.JK.currentUserId,
user_name: context.JK.currentUserName
})
if !response.first_opened_jamtrack_web_player
setTimeout((() =>
logger.debug("first time user")
rest.userOpenedJamTrackWebPlayer()
$root = $(@getDOMNode())
#context.JK.prodBubble($root.find('.create-mix-btn'), 'first-time-jamtrack-web-player', {}, {positions:['left'], offsetParent: $root})
), 1500)
)
componentDidMount: () ->
$(window).unload(@windowUnloaded)
@root = jQuery(this.getDOMNode())
$loop = @root.find('input[name="loop"]')
context.JK.checkbox($loop)
$loop.on('ifChecked', () =>
# it doesn't matter if you do personal or master, because backend just syncs both
MixerActions.loopChanged(@state.media.backingTracks[0].mixers.personal.mixer, true)
)
$loop.on('ifUnchecked', () =>
# it doesn't matter if you do personal or master, because backend just syncs both
MixerActions.loopChanged(@state.media.backingTracks[0].mixers.personal.mixer, false)
)
@resizeWindow()
# this is necessary due to whatever the client's rendering behavior is.
setTimeout(@resizeWindow, 300)
@fetchJamTrackInfo()
componentDidUpdate: () ->
@resizeWindow()
setTimeout(@resizeWindow, 1000)
resizeWindow: () =>
return
$container = $('#minimal-container')
width = $container.width()
height = $container.height()
# there is 20px or so of unused space at the top of the page. can't figure out why it's there. (above #minimal-container)
#mysteryTopMargin = 20
mysteryTopMargin = 0
# deal with chrome in real browsers
offset = (window.outerHeight - window.innerHeight) + mysteryTopMargin
# handle native client chrome that the above outer-inner doesn't catch
#if navigator.userAgent.indexOf('JamKazam') > -1
#offset += 25
window.resizeTo(450, height + offset)
computeDisableLoading: (state) ->
@disableLoading = false
return unless nextState?
selectedMixdown = state?.jamTrackState?.jamTrack?.activeMixdown
mixdownDownloading = false
if selectedMixdown?
switch selectedMixdown.client_state
when 'downloading'
mixdownDownloading = true
selectedStem = state?.jamTrackState?.jamTrack?.activeStem
stemDownloading = false
if selectedStem?
switch selectedStem.client_state
when 'downloading'
stemDownloading = true
@disableLoading = state?.jamTrackState?.jamTrack?.client_state == 'downloading' || mixdownDownloading || stemDownloading
componentWillMount: () ->
@computeDisableLoading(@state)
componentWillUpdate: (nextProps, nextState) ->
@computeDisableLoading(nextState)
})