VRFS-3936 merging develop
This commit is contained in:
commit
f07465f372
|
|
@ -33,6 +33,7 @@ ActiveAdmin.register_page "Fake Purchaser" do
|
||||||
jam_track_right.jam_track = jam_track
|
jam_track_right.jam_track = jam_track
|
||||||
jam_track_right.is_test_purchase = true
|
jam_track_right.is_test_purchase = true
|
||||||
jam_track_right.version = jam_track.version
|
jam_track_right.version = jam_track.version
|
||||||
|
jam_track_right.can_download = true
|
||||||
jam_track_right.save!
|
jam_track_right.save!
|
||||||
count = count + 1
|
count = count + 1
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -375,3 +375,4 @@ teacher_distribution_fields.sql
|
||||||
jam_track_download_rights.sql
|
jam_track_download_rights.sql
|
||||||
guitar_center_integration_v1.sql
|
guitar_center_integration_v1.sql
|
||||||
mobile_recording_support.sql
|
mobile_recording_support.sql
|
||||||
|
youtube_broadcast.sql
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
CREATE TABLE broadcasts (
|
||||||
|
id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||||
|
music_session_id VARCHAR(64) NOT NULL REFERENCES music_sessions(id) ON DELETE CASCADE,
|
||||||
|
user_id VARCHAR(64) NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||||
|
broadcast_id VARCHAR NOT NULL,
|
||||||
|
stream_id VARCHAR,
|
||||||
|
broadcast_status VARCHAR,
|
||||||
|
stream_status VARCHAR,
|
||||||
|
stream_name VARCHAR,
|
||||||
|
stream_address VARCHAR,
|
||||||
|
broadcast_data VARCHAR,
|
||||||
|
stream_data VARCHAR,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX idx_broadcast_broadcast_id ON broadcasts USING BTREE(broadcast_id);
|
||||||
|
CREATE INDEX idx_broadcast_status ON broadcasts USING BTREE(broadcast_status);
|
||||||
|
CREATE INDEX idx_stream_status ON broadcasts USING BTREE(stream_status);
|
||||||
|
|
||||||
|
CREATE INDEX idx_broadcast_music_session_id ON broadcasts USING BTREE(music_session_id);
|
||||||
|
|
@ -155,6 +155,7 @@ require "jam_ruby/models/friendship"
|
||||||
require "jam_ruby/models/active_music_session"
|
require "jam_ruby/models/active_music_session"
|
||||||
require "jam_ruby/models/music_session_comment"
|
require "jam_ruby/models/music_session_comment"
|
||||||
require "jam_ruby/models/session_info_comment"
|
require "jam_ruby/models/session_info_comment"
|
||||||
|
require "jam_ruby/models/broadcast"
|
||||||
require "jam_ruby/models/music_session"
|
require "jam_ruby/models/music_session"
|
||||||
require "jam_ruby/models/music_session_liker"
|
require "jam_ruby/models/music_session_liker"
|
||||||
require "jam_ruby/models/music_session_user_history"
|
require "jam_ruby/models/music_session_user_history"
|
||||||
|
|
|
||||||
|
|
@ -527,6 +527,12 @@ module JamRuby
|
||||||
@storage_format == 'Drumma'
|
@storage_format == 'Drumma'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def is_clevie_storage?
|
||||||
|
assert_storage_set
|
||||||
|
@storage_format == 'Clevie'
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
def assert_storage_set
|
def assert_storage_set
|
||||||
raise "no storage_format set" if @storage_format.nil?
|
raise "no storage_format set" if @storage_format.nil?
|
||||||
end
|
end
|
||||||
|
|
@ -534,7 +540,7 @@ module JamRuby
|
||||||
|
|
||||||
def parse_metalocation(metalocation)
|
def parse_metalocation(metalocation)
|
||||||
# metalocation = mapped/4 Non Blondes - What's Up - 6475/meta.yml
|
# metalocation = mapped/4 Non Blondes - What's Up - 6475/meta.yml
|
||||||
if is_drumma_storage?
|
if is_drumma_storage? || is_clevie_storage?
|
||||||
|
|
||||||
suffix = '/meta.yml'
|
suffix = '/meta.yml'
|
||||||
|
|
||||||
|
|
@ -898,6 +904,9 @@ module JamRuby
|
||||||
elsif is_drumma_storage?
|
elsif is_drumma_storage?
|
||||||
jam_track.vendor_id = metadata[:id]
|
jam_track.vendor_id = metadata[:id]
|
||||||
jam_track.licensor = JamTrackLicensor.find_by_name!('Drumma Boy')
|
jam_track.licensor = JamTrackLicensor.find_by_name!('Drumma Boy')
|
||||||
|
elsif is_clevie_storage?
|
||||||
|
jam_track.vendor_id = metadata[:id]
|
||||||
|
jam_track.licensor = JamTrackLicensor.find_by_name!('Steely & Clevie')
|
||||||
end
|
end
|
||||||
jam_track.slug = metadata['slug']
|
jam_track.slug = metadata['slug']
|
||||||
if jam_track.slug.nil?
|
if jam_track.slug.nil?
|
||||||
|
|
@ -2247,6 +2256,8 @@ module JamRuby
|
||||||
tim_tracks_s3_manager
|
tim_tracks_s3_manager
|
||||||
elsif is_drumma_storage?
|
elsif is_drumma_storage?
|
||||||
drumma_s3_manager
|
drumma_s3_manager
|
||||||
|
elsif is_clevie_storage?
|
||||||
|
clevie_s3_manager
|
||||||
elsif is_helbing_storage?
|
elsif is_helbing_storage?
|
||||||
helbing_s3_manager
|
helbing_s3_manager
|
||||||
else
|
else
|
||||||
|
|
@ -2262,6 +2273,10 @@ module JamRuby
|
||||||
@drumma_s3_manager ||= S3Manager.new('jamkazam-drumma', APP_CONFIG.aws_access_key_id, APP_CONFIG.aws_secret_access_key)
|
@drumma_s3_manager ||= S3Manager.new('jamkazam-drumma', APP_CONFIG.aws_access_key_id, APP_CONFIG.aws_secret_access_key)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def clevie_s3_manager
|
||||||
|
@clevie_s3_manager ||= S3Manager.new('jamkazam-clevie', APP_CONFIG.aws_access_key_id, APP_CONFIG.aws_secret_access_key)
|
||||||
|
end
|
||||||
|
|
||||||
def tency_s3_manager
|
def tency_s3_manager
|
||||||
@tency_s3_manager ||= S3Manager.new('jamkazam-tency', APP_CONFIG.aws_access_key_id, APP_CONFIG.aws_secret_access_key)
|
@tency_s3_manager ||= S3Manager.new('jamkazam-tency', APP_CONFIG.aws_access_key_id, APP_CONFIG.aws_secret_access_key)
|
||||||
end
|
end
|
||||||
|
|
@ -2335,6 +2350,11 @@ module JamRuby
|
||||||
@storage_format == 'Drumma'
|
@storage_format == 'Drumma'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def is_clevie_storage?
|
||||||
|
assert_storage_set
|
||||||
|
@storage_format == 'Clevie'
|
||||||
|
end
|
||||||
|
|
||||||
def is_tency_storage?
|
def is_tency_storage?
|
||||||
assert_storage_set
|
assert_storage_set
|
||||||
@storage_format == 'Tency'
|
@storage_format == 'Tency'
|
||||||
|
|
@ -2446,6 +2466,19 @@ module JamRuby
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def iterate_clevie_song_storage(&blk)
|
||||||
|
song_storage_manager.list_directories.each do |song|
|
||||||
|
@@log.debug("searching through song directory '#{song}'")
|
||||||
|
|
||||||
|
metalocation = "#{song}meta.yml"
|
||||||
|
|
||||||
|
metadata = load_metalocation(metalocation)
|
||||||
|
|
||||||
|
blk.call(metadata, metalocation)
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def iterate_helbing_song_storage(&blk)
|
def iterate_helbing_song_storage(&blk)
|
||||||
count = 0
|
count = 0
|
||||||
song_storage_manager.list_directories('mapped').each do |song|
|
song_storage_manager.list_directories('mapped').each do |song|
|
||||||
|
|
@ -2479,6 +2512,10 @@ module JamRuby
|
||||||
iterate_drumma_song_storage do |metadata, metalocation|
|
iterate_drumma_song_storage do |metadata, metalocation|
|
||||||
blk.call(metadata, metalocation)
|
blk.call(metadata, metalocation)
|
||||||
end
|
end
|
||||||
|
elsif is_clevie_storage?
|
||||||
|
iterate_clevie_song_storage do |metadata, metalocation|
|
||||||
|
blk.call(metadata, metalocation)
|
||||||
|
end
|
||||||
elsif is_helbing_storage?
|
elsif is_helbing_storage?
|
||||||
iterate_helbing_song_storage do |metadata, metalocation|
|
iterate_helbing_song_storage do |metadata, metalocation|
|
||||||
blk.call(metadata, metalocation)
|
blk.call(metadata, metalocation)
|
||||||
|
|
@ -3487,6 +3524,17 @@ module JamRuby
|
||||||
meta = YAML.load(data)
|
meta = YAML.load(data)
|
||||||
meta[:genres] = ['r&b'] if !meta[:genres]
|
meta[:genres] = ['r&b'] if !meta[:genres]
|
||||||
meta
|
meta
|
||||||
|
elsif is_clevie_storage?
|
||||||
|
|
||||||
|
data = {}
|
||||||
|
begin
|
||||||
|
data = clevie_s3_manager.read_all(metalocation)
|
||||||
|
rescue AWS::S3::Errors::NoSuchKey
|
||||||
|
return {}
|
||||||
|
end
|
||||||
|
meta = YAML.load(data)
|
||||||
|
meta[:genres] = ['reggae'] if !meta[:genres]
|
||||||
|
meta
|
||||||
else
|
else
|
||||||
begin
|
begin
|
||||||
data = s3_manager.read_all(metalocation)
|
data = s3_manager.read_all(metalocation)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
|
||||||
|
module JamRuby
|
||||||
|
class Broadcast < ActiveRecord::Base
|
||||||
|
|
||||||
|
@@log = Logging.logger[Broadcast]
|
||||||
|
|
||||||
|
STATUS_COMPLETED = 'completed'
|
||||||
|
STATUS_ABANDONED = 'abandoned'
|
||||||
|
STATUS_REVOKED = 'revoked'
|
||||||
|
|
||||||
|
DONE_STATUSES = [STATUS_COMPLETED, STATUS_ABANDONED, STATUS_REVOKED]
|
||||||
|
belongs_to :music_session, :class_name => 'JamRuby::MusicSsession'
|
||||||
|
|
||||||
|
def self.current_broadcast(music_session)
|
||||||
|
Broadcast.where(music_session_id: music_session.id).where('broadcast_status not in (?)', Broadcast::DONE_STATUSES).first
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -54,6 +54,7 @@ module JamRuby
|
||||||
has_many :rsvp_slots, :class_name => "JamRuby::RsvpSlot", :foreign_key => "music_session_id", :dependent => :destroy
|
has_many :rsvp_slots, :class_name => "JamRuby::RsvpSlot", :foreign_key => "music_session_id", :dependent => :destroy
|
||||||
has_many :music_notations, :class_name => "JamRuby::MusicNotation", :foreign_key => "music_session_id"
|
has_many :music_notations, :class_name => "JamRuby::MusicNotation", :foreign_key => "music_session_id"
|
||||||
has_many :jam_track_session, :class_name => "JamRuby::JamTrackSession"
|
has_many :jam_track_session, :class_name => "JamRuby::JamTrackSession"
|
||||||
|
has_many :broadcasts, :class_name => "JamRuby::Broadcast"
|
||||||
|
|
||||||
validates :genre, :presence => true
|
validates :genre, :presence => true
|
||||||
validates :description, :presence => true, :no_profanity => true
|
validates :description, :presence => true, :no_profanity => true
|
||||||
|
|
@ -78,6 +79,135 @@ module JamRuby
|
||||||
|
|
||||||
SEPARATOR = '|'
|
SEPARATOR = '|'
|
||||||
|
|
||||||
|
def current_broadcast
|
||||||
|
Broadcast.current_broadcast(self)
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_broadcast(google_client, user, broadcast_options)
|
||||||
|
|
||||||
|
broadcast = current_broadcast
|
||||||
|
|
||||||
|
if broadcast.nil?
|
||||||
|
broadcast = create_youtube_broadcast(google_client, user, broadcast_options)
|
||||||
|
else
|
||||||
|
refresh_youtube_broadcast(google_client, user, broadcast)
|
||||||
|
# check against Youtube the real state of broadcast, to see if we need a new one?
|
||||||
|
end
|
||||||
|
|
||||||
|
broadcast
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_stream(google_client, user, broadcast_options)
|
||||||
|
|
||||||
|
broadcast = create_broadcast(google_client, user, broadcast_options)
|
||||||
|
|
||||||
|
stream = current_stream(broadcast)
|
||||||
|
|
||||||
|
if stream.nil?
|
||||||
|
create_youtube_stream(google_client, user, broadcast, broadcast_options)
|
||||||
|
bind_broadcast(google_client, user, broadcast)
|
||||||
|
else
|
||||||
|
bind_broadcast(google_client, user, broadcast)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def current_stream(broadcast)
|
||||||
|
broadcast.stream_id
|
||||||
|
end
|
||||||
|
|
||||||
|
def refresh_youtube_broadcast(google_client, user, broadcast)
|
||||||
|
broadcast_data = google_client.get_broadcast(user, broadcast.broadcast_id)
|
||||||
|
broadcast.broadcast_status = broadcast_data["status"]["lifeCycleStatus"]
|
||||||
|
broadcast.broadcast_data = broadcast_data.to_json
|
||||||
|
end
|
||||||
|
|
||||||
|
# https://developers.google.com/youtube/v3/live/docs/liveStreams#resource
|
||||||
|
def create_youtube_stream(google_client, user, broadcast, broadcast_options)
|
||||||
|
|
||||||
|
# https://developers.google.com/youtube/v3/live/docs/liveStreams/insert
|
||||||
|
# required
|
||||||
|
# snippet.title
|
||||||
|
# cdn.format
|
||||||
|
# cdn.ingestionType (deprecated - use resolution/framerate)
|
||||||
|
|
||||||
|
stream_options = {}
|
||||||
|
stream_options[:snippet] ||= {}
|
||||||
|
stream_options[:snippet][:title] ||= name
|
||||||
|
stream_options[:snippet][:isDefaultStream] = false
|
||||||
|
#broadcast_options[:snippet][:scheduledEndTime] = end_time.utc.iso8601
|
||||||
|
|
||||||
|
stream_options[:cdn] ||= {}
|
||||||
|
stream_options[:cdn][:frameRate] ||= '30fps'
|
||||||
|
stream_options[:cdn][:resolution] ||= '360p'
|
||||||
|
stream_options[:cdn][:ingestionType] ||= 'rtmp'
|
||||||
|
|
||||||
|
stream_options[:contentDetails] ||= {}
|
||||||
|
stream_options[:contentDetails][:isReusable] = false
|
||||||
|
|
||||||
|
stream_options = google_client.create_stream(user, stream_options)
|
||||||
|
|
||||||
|
broadcast.stream_id = stream_options["id"]
|
||||||
|
broadcast.stream_status = stream_options["status"]["streamStatus"]
|
||||||
|
broadcast.stream_name = stream_options["cdn"]["ingestionInfo"]["streamName"]
|
||||||
|
broadcast.stream_address = stream_options["cdn"]["ingestionInfo"]["ingestionAddress"]
|
||||||
|
broadcast.stream_data = stream_options.to_json
|
||||||
|
broadcast.save!
|
||||||
|
broadcast
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_youtube_broadcast(google_client, user, broadcast_options)
|
||||||
|
|
||||||
|
start_time, end_time = youtube_times
|
||||||
|
broadcast_options ||= {}
|
||||||
|
broadcast_options[:snippet] ||= {}
|
||||||
|
broadcast_options[:snippet][:title] ||= name
|
||||||
|
broadcast_options[:snippet][:description] ||= description
|
||||||
|
broadcast_options[:snippet][:scheduledStartTime] = start_time.utc.iso8601
|
||||||
|
#broadcast_options[:snippet][:scheduledEndTime] = end_time.utc.iso8601
|
||||||
|
|
||||||
|
broadcast_options[:status] ||= {}
|
||||||
|
broadcast_options[:status][:privacyStatus] ||= (fan_access ? 'public' : 'private')
|
||||||
|
|
||||||
|
broadcast_options[:contentDetails] ||= {}
|
||||||
|
|
||||||
|
# if false, this causes a 'request not authorized error'
|
||||||
|
# From: https://developers.google.com/youtube/v3/live/docs/liveBroadcasts
|
||||||
|
# If your channel does not have permission to disable recordings, and you attempt to insert a broadcast with the recordFromStart property set to false, the API will return a Forbidden error.
|
||||||
|
#broadcast_options[:contentDetails][:recordFromStart] ||= false
|
||||||
|
|
||||||
|
broadcast_data = google_client.create_broadcast(user, broadcast_options)
|
||||||
|
|
||||||
|
broadcast = Broadcast.new
|
||||||
|
broadcast.music_session_id = self.id
|
||||||
|
broadcast.user_id = user.id
|
||||||
|
broadcast.broadcast_id = broadcast_data["id"]
|
||||||
|
broadcast.broadcast_status = broadcast_data["status"]["lifeCycleStatus"]
|
||||||
|
broadcast.broadcast_data = broadcast_data.to_json
|
||||||
|
broadcast.save!
|
||||||
|
broadcast
|
||||||
|
end
|
||||||
|
|
||||||
|
def bind_broadcast(google_client, user, broadcast)
|
||||||
|
|
||||||
|
bind_data = google_client.bind_broadcast(user, broadcast.broadcast_id, broadcast.stream_id)
|
||||||
|
broadcast.broadcast_data = bind_data.to_json
|
||||||
|
broadcast.save!
|
||||||
|
broadcast
|
||||||
|
end
|
||||||
|
|
||||||
|
def youtube_times
|
||||||
|
start = scheduled_start_time
|
||||||
|
|
||||||
|
if start < Time.now
|
||||||
|
start = Time.now
|
||||||
|
end_time = start + safe_scheduled_duration
|
||||||
|
return [start, end_time]
|
||||||
|
else
|
||||||
|
return [start, scheduled_end_time]
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
def check_scheduling_info_changed
|
def check_scheduling_info_changed
|
||||||
@scheduling_info_changed = scheduled_start_changed?
|
@scheduling_info_changed = scheduled_start_changed?
|
||||||
true
|
true
|
||||||
|
|
@ -574,7 +704,9 @@ module JamRuby
|
||||||
end
|
end
|
||||||
|
|
||||||
def scheduled_end_time
|
def scheduled_end_time
|
||||||
|
start = scheduled_start_time
|
||||||
|
duration = safe_scheduled_duration
|
||||||
|
start + duration
|
||||||
end
|
end
|
||||||
|
|
||||||
def timezone_id
|
def timezone_id
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ module JamRuby
|
||||||
self
|
self
|
||||||
.where(:user_id => user.id)
|
.where(:user_id => user.id)
|
||||||
.where(:provider => 'google_login')
|
.where(:provider => 'google_login')
|
||||||
.where(['token_expiration IS NULL OR token_expiration > ?', Time.now])
|
.where(['token_expiration IS NULL OR (token_expiration > ? OR refresh_token is not null)', Time.now])
|
||||||
.limit(1)
|
.limit(1)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1752,6 +1752,7 @@
|
||||||
this.isSessVideoShared = isSessVideoShared;
|
this.isSessVideoShared = isSessVideoShared;
|
||||||
this.SessStopVideoSharing = SessStopVideoSharing;
|
this.SessStopVideoSharing = SessStopVideoSharing;
|
||||||
this.SessStartVideoSharing = SessStartVideoSharing;
|
this.SessStartVideoSharing = SessStartVideoSharing;
|
||||||
|
this.getOpenVideoSources = getOpenVideoSources;
|
||||||
|
|
||||||
// Clipboard
|
// Clipboard
|
||||||
this.SaveToClipboard = SaveToClipboard;
|
this.SaveToClipboard = SaveToClipboard;
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@ logger = context.JK.logger
|
||||||
NoVideoRecordActive = 0
|
NoVideoRecordActive = 0
|
||||||
WebCamRecordActive = 1
|
WebCamRecordActive = 1
|
||||||
ScreenRecordActive = 2
|
ScreenRecordActive = 2
|
||||||
|
WebCam2RecordActive = 3
|
||||||
|
DesktopRecordActive = 4
|
||||||
|
|
||||||
mixins = []
|
mixins = []
|
||||||
|
|
||||||
|
|
@ -53,20 +55,42 @@ if accessOpener
|
||||||
|
|
||||||
if @inputType != 'audio-only'
|
if @inputType != 'audio-only'
|
||||||
|
|
||||||
if $root.find('#recording-selection').val() == 'video-window'
|
selection = $root.find('#recording-selection').val()
|
||||||
|
|
||||||
|
if selection == 'video-window'
|
||||||
recordVideo = ScreenRecordActive
|
recordVideo = ScreenRecordActive
|
||||||
else
|
else if selection == 'webcam-only'
|
||||||
recordVideo = WebCamRecordActive
|
recordVideo = WebCamRecordActive
|
||||||
|
else if selection == 'webcam-only-2'
|
||||||
|
recordVideo = WebCam2RecordActive
|
||||||
|
else
|
||||||
|
recordVideo = DesktopRecordActive
|
||||||
|
|
||||||
|
|
||||||
recordChat = $root.find('#include-chat').is(':checked')
|
recordChat = $root.find('#include-chat').is(':checked')
|
||||||
|
|
||||||
|
|
||||||
# if the video window isn't open, but a video option was selected...
|
# if the video window isn't open, but a video option was selected...
|
||||||
if recordVideo != NoVideoRecordActive && !VideoStore.videoShared
|
window.opener.VideoActions.refreshVideoState.trigger()
|
||||||
|
|
||||||
|
if recordVideo != NoVideoRecordActive && !VideoStore.anyVideoOpen
|
||||||
|
#if recordVideo != NoVideoRecordActive && !VideoStore.videoShared
|
||||||
logger.debug("prevent video from opening", VideoStore)
|
logger.debug("prevent video from opening", VideoStore)
|
||||||
context.JK.prodBubble($root.find('.control'), 'video-window-not-open', {}, {positions:['bottom']})
|
context.JK.prodBubble($root.find('.control'), 'video-window-not-open', {}, {positions:['bottom']})
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if recordVideo == WebCamRecordActive && !VideoStore.openVideoSources.webcam1
|
||||||
|
context.JK.prodBubble($root.find('.control'), 'no-webcam-1', {}, {positions:['bottom']})
|
||||||
|
return
|
||||||
|
|
||||||
|
if recordVideo == WebCam2RecordActive && !VideoStore.openVideoSources.webcam2
|
||||||
|
context.JK.prodBubble($root.find('.control'), 'no-webcam-2', {}, {positions:['bottom']})
|
||||||
|
return
|
||||||
|
|
||||||
|
if recordVideo == DesktopRecordActive && !VideoStore.openVideoSources.screen_capture
|
||||||
|
context.JK.prodBubble($root.find('.control'), 'no-screen-capture', {}, {positions:['bottom']})
|
||||||
|
return
|
||||||
|
|
||||||
logger.debug("@inputType, @udiotye", recordChat, recordVideo)
|
logger.debug("@inputType, @udiotye", recordChat, recordVideo)
|
||||||
window.opener.RecordingActions.startRecording(recordVideo, recordChat)
|
window.opener.RecordingActions.startRecording(recordVideo, recordChat)
|
||||||
|
|
||||||
|
|
@ -120,6 +144,8 @@ if accessOpener
|
||||||
<select className="easydropdown" name="recording-selection" id="recording-selection">
|
<select className="easydropdown" name="recording-selection" id="recording-selection">
|
||||||
<option value="video-window">Record session video window</option>
|
<option value="video-window">Record session video window</option>
|
||||||
<option value="webcam-only">Record my webcam only</option>
|
<option value="webcam-only">Record my webcam only</option>
|
||||||
|
<option value="webcam-only-2">Record my 2nd webcam only</option>
|
||||||
|
<option value="desktop-only">Record my computer desktop</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -14,4 +14,5 @@ context = window
|
||||||
configureVideoPopupClosed: {}
|
configureVideoPopupClosed: {}
|
||||||
checkPromptConfigureVideo: {}
|
checkPromptConfigureVideo: {}
|
||||||
setVideoEnabled: {}
|
setVideoEnabled: {}
|
||||||
|
refreshVideoState: {}
|
||||||
})
|
})
|
||||||
|
|
@ -137,6 +137,22 @@ BackendToFrontendFPS = {
|
||||||
@state.currentFrameRate = frameRates
|
@state.currentFrameRate = frameRates
|
||||||
this.trigger(@state)
|
this.trigger(@state)
|
||||||
|
|
||||||
|
onRefreshVideoState:()->
|
||||||
|
@logger.debug("onRefreshVideoState")
|
||||||
|
openVideoSources = context.jamClient.getOpenVideoSources()
|
||||||
|
@logger.debug("onRefreshVideoState", openVideoSources)
|
||||||
|
|
||||||
|
# possible keys, all bool values
|
||||||
|
#"session_window", "webcam1", "webcam2", "screen_capture"
|
||||||
|
|
||||||
|
# ex: with mac webcam open only: session_window: 2, webcam1: 1}
|
||||||
|
# no webcam open: Object {}
|
||||||
|
|
||||||
|
@openVideoSources = openVideoSources
|
||||||
|
@anyVideoOpen = Object.keys(openVideoSources).length > 0
|
||||||
|
@state.anyVideoOpen = Object.keys(openVideoSources).length > 0
|
||||||
|
this.trigger(@state)
|
||||||
|
|
||||||
onSelectDevice: (device, caps) ->
|
onSelectDevice: (device, caps) ->
|
||||||
|
|
||||||
# don't do anything if no video capabilities
|
# don't do anything if no video capabilities
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,58 @@
|
||||||
|
@import "client/common";
|
||||||
|
|
||||||
|
body.video-stream {
|
||||||
|
|
||||||
|
position: relative;
|
||||||
|
color: $ColorTextTypical;
|
||||||
|
|
||||||
|
#minimal-container {
|
||||||
|
padding-bottom: 20px;
|
||||||
|
height:240px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.video-stream {
|
||||||
|
padding-left: 30px;
|
||||||
|
padding-right:30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
margin-top:20px;
|
||||||
|
font-size:16px;
|
||||||
|
font-weight:bold;
|
||||||
|
margin-bottom:20px;
|
||||||
|
text-align:center;
|
||||||
|
line-height:125%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.control-holder {
|
||||||
|
margin: 20px 0 20px;
|
||||||
|
text-align:center;
|
||||||
|
padding-bottom:20px;
|
||||||
|
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
width: 100%;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-bar {
|
||||||
|
background-color:#ED3618;
|
||||||
|
border:solid 1px #000;
|
||||||
|
height:20px;
|
||||||
|
display:block;
|
||||||
|
@include border_box_sizing;
|
||||||
|
margin:20px 0;
|
||||||
|
position:relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.percentage-progress {
|
||||||
|
position:absolute;
|
||||||
|
right:-32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.video-url {
|
||||||
|
text-align:center;
|
||||||
|
display:block;
|
||||||
|
margin:20px 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -168,7 +168,7 @@ class LandingsController < ApplicationController
|
||||||
instrument = params[:instrument].downcase.sub('-', ' ')
|
instrument = params[:instrument].downcase.sub('-', ' ')
|
||||||
instrument = Instrument.find_by_id(instrument)
|
instrument = Instrument.find_by_id(instrument)
|
||||||
instrument_id = instrument.id if instrument
|
instrument_id = instrument.id if instrument
|
||||||
instrument_name = instrument.description
|
instrument_name = instrument .description
|
||||||
query, next_ptr, instrument_count = JamTrack.index({instrument: instrument_id}, current_user)
|
query, next_ptr, instrument_count = JamTrack.index({instrument: instrument_id}, current_user)
|
||||||
end
|
end
|
||||||
@jam_track = JamTrack.find_by_slug(params[:plan_code])
|
@jam_track = JamTrack.find_by_slug(params[:plan_code])
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,13 @@ class PopupsController < ApplicationController
|
||||||
render :layout => "minimal"
|
render :layout => "minimal"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
def video_stream
|
||||||
|
@session_id = params[:session_id]
|
||||||
|
gon.session_id= @session_id
|
||||||
|
render :layout => "minimal"
|
||||||
|
end
|
||||||
|
|
||||||
def jamtrack_player
|
def jamtrack_player
|
||||||
enable_olark
|
enable_olark
|
||||||
@jamtrack_id = params[:jam_track_id]
|
@jamtrack_id = params[:jam_track_id]
|
||||||
|
|
|
||||||
|
|
@ -371,6 +371,18 @@ script type="text/template" id="template-help-video-window-not-open"
|
||||||
p You've selected to record video, but the video window is not open.
|
p You've selected to record video, but the video window is not open.
|
||||||
p Click the VIDEO button in the main window and try again.
|
p Click the VIDEO button in the main window and try again.
|
||||||
|
|
||||||
|
script type="text/template" id="template-help-no-webcam-1"
|
||||||
|
.video-window-not-open
|
||||||
|
p You've selected to record your primary webcam, but it is not open.
|
||||||
|
|
||||||
|
script type="text/template" id="template-help-no-webcam-2"
|
||||||
|
.video-window-not-open
|
||||||
|
p You've selected to record your secondary webcam, but it is not open.
|
||||||
|
|
||||||
|
script type="text/template" id="template-help-no-screen-capture"
|
||||||
|
.video-window-not-open
|
||||||
|
p You've selected to record your desktop, but that feature is not enabled.
|
||||||
|
|
||||||
script type="text/template" id="template-help-vid-record-chat-input"
|
script type="text/template" id="template-help-vid-record-chat-input"
|
||||||
.vid-record-chat-input
|
.vid-record-chat-input
|
||||||
p Any chat inputs in the session will also be included in the video if checked.
|
p Any chat inputs in the session will also be included in the video if checked.
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
- provide(:page_name, 'video-stream popup')
|
||||||
|
- provide(:title, 'Video Stream')
|
||||||
|
= react_component 'PopupVideoStreamer', {}
|
||||||
|
|
@ -2,7 +2,7 @@ Rails.application.config.middleware.use OmniAuth::Builder do
|
||||||
provider :facebook, Rails.application.config.facebook_app_id, Rails.application.config.facebook_app_secret, {name: "facebook", :scope => 'email,user_location'}
|
provider :facebook, Rails.application.config.facebook_app_id, Rails.application.config.facebook_app_secret, {name: "facebook", :scope => 'email,user_location'}
|
||||||
# add these back later if needed
|
# add these back later if needed
|
||||||
# userinfo.email, userinfo.profile, https://www.google.com/m8/feeds,
|
# userinfo.email, userinfo.profile, https://www.google.com/m8/feeds,
|
||||||
provider :google_oauth2, Rails.application.config.google_client_id, Rails.application.config.google_secret, {name: "google_login", prompt: 'consent', scope: 'userinfo.email, https://www.googleapis.com/auth/youtube.upload, https://www.googleapis.com/auth/youtube'}
|
provider :google_oauth2, Rails.application.config.google_client_id, Rails.application.config.google_secret, {name: "google_login", prompt: 'consent', scope: ['youtube', 'youtube.force-ssl', 'youtube.upload','userinfo.email','userinfo.profile']}
|
||||||
provider :twitter, Rails.application.config.twitter_app_id, Rails.application.config.twitter_app_secret, {x_auth_access_type: 'write' }
|
provider :twitter, Rails.application.config.twitter_app_id, Rails.application.config.twitter_app_secret, {x_auth_access_type: 'write' }
|
||||||
provider :stripe_connect, Rails.application.config.stripe[:client_id], Rails.application.config.stripe[:secret_key], {}
|
provider :stripe_connect, Rails.application.config.stripe[:client_id], Rails.application.config.stripe[:secret_key], {}
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -178,6 +178,7 @@ Rails.application.routes.draw do
|
||||||
get '/video/upload/:recording_id', to: 'popups#video_upload'
|
get '/video/upload/:recording_id', to: 'popups#video_upload'
|
||||||
get '/jamtrack-player/:jam_track_id', to: 'popups#jamtrack_player'
|
get '/jamtrack-player/:jam_track_id', to: 'popups#jamtrack_player'
|
||||||
get '/jamtrack/download/:jam_track_id/mixdowns/:jam_track_mixdown_id', to: 'popups#jamtrack_download'
|
get '/jamtrack/download/:jam_track_id/mixdowns/:jam_track_mixdown_id', to: 'popups#jamtrack_download'
|
||||||
|
get '/video/stream/:session_id', to: 'popups#video_stream'
|
||||||
end
|
end
|
||||||
|
|
||||||
scope '/corp' do
|
scope '/corp' do
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,11 @@ require 'google/api_client/client_secrets'
|
||||||
require 'google/api_client/auth/installed_app'
|
require 'google/api_client/auth/installed_app'
|
||||||
require 'socket'
|
require 'socket'
|
||||||
|
|
||||||
|
#Google::Apis.logger.level = Logger::DEBUG
|
||||||
|
|
||||||
|
YOUTUBE_API_SERVICE_NAME = 'youtube'
|
||||||
|
YOUTUBE_API_VERSION = 'v3'
|
||||||
|
|
||||||
# Youtube OAuth and API functionality:
|
# Youtube OAuth and API functionality:
|
||||||
module JamRuby
|
module JamRuby
|
||||||
class GoogleClient
|
class GoogleClient
|
||||||
|
|
@ -19,21 +24,56 @@ module JamRuby
|
||||||
attr_accessor :redirect_uri
|
attr_accessor :redirect_uri
|
||||||
|
|
||||||
def initialize()
|
def initialize()
|
||||||
Rails.logger.info("Initializing client...")
|
|
||||||
self.config = Rails.application.config
|
self.config = Rails.application.config
|
||||||
self.redirect_uri='http://localhost:2112/auth/google_login/callback'
|
self.redirect_uri='http://localhost:2112/auth/google_login/callback'
|
||||||
self.client = Google::APIClient.new(
|
self.client = Google::APIClient.new(
|
||||||
:application_name => 'JamKazam',
|
:application_name => 'JamKazam',
|
||||||
:application_version => '1.0.0'
|
:application_version => '1.0.0'
|
||||||
)
|
)
|
||||||
|
|
||||||
#youtube = client.discovered_api('youtube', 'v3')
|
end
|
||||||
|
|
||||||
|
def youtube
|
||||||
|
@youtube ||= client.discovered_api('youtube', 'v3')
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_authorization(user_auth, scope, autorefresh)
|
||||||
|
|
||||||
|
authorization = Signet::OAuth2::Client.new(
|
||||||
|
:authorization_uri => "https://accounts.google.com/o/oauth2/auth",
|
||||||
|
:token_credential_uri => "https://accounts.google.com/o/oauth2/token",
|
||||||
|
:client_id => @config.google_client_id,
|
||||||
|
:client_secret => @config.google_secret,
|
||||||
|
#:redirect_uri => credentials.redirect_uris.first,
|
||||||
|
:scope => scope
|
||||||
|
)
|
||||||
|
authorization.access_token = user_auth.token
|
||||||
|
authorization.refresh_token = user_auth.refresh_token
|
||||||
|
authorization.expires_at = user_auth.token_expiration
|
||||||
|
|
||||||
|
if autorefresh && (user_auth.token_expiration < (Time.now - 15)) # add 15 second buffer to this time, because OAUth server does not respond with timestamp, but 'expires_in' which is just offset seconds
|
||||||
|
|
||||||
|
# XXX: what to do when this fails?
|
||||||
|
authorization.refresh!
|
||||||
|
user_auth.token = authorization.access_token
|
||||||
|
user_auth.token_expiration = authorization.issued_at + authorization.expires_in
|
||||||
|
user_auth.save
|
||||||
|
end
|
||||||
|
authorization
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_client
|
||||||
|
Google::APIClient.new(
|
||||||
|
:application_name => 'JamKazam',
|
||||||
|
:application_version => '1.0.0',
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Return a login URL that will show a web page with
|
# Return a login URL that will show a web page with
|
||||||
def get_login_url(username=nil)
|
def get_login_url(username=nil)
|
||||||
|
puts "GET LOGIN URL"
|
||||||
uri = "https://accounts.google.com/o/oauth2/auth"
|
uri = "https://accounts.google.com/o/oauth2/auth"
|
||||||
uri << "?scope=#{CGI.escape('https://www.googleapis.com/auth/youtube https://www.googleapis.com/auth/youtube.upload https://gdata.youtube.com email profile ')}" # # https://www.googleapis.com/auth/youtube https://www.googleapis.com/auth/youtube.upload
|
uri << "?scope=#{CGI.escape('https://www.googleapis.com/auth/youtube https://www.googleapis.com/auth/youtube.upload https://www.googleapis.com/auth/youtube https://gdata.youtube.com email profile ')}" # # https://www.googleapis.com/auth/youtube https://www.googleapis.com/auth/youtube.upload
|
||||||
uri << "&client_id=#{CGI.escape(self.config.google_email)}"
|
uri << "&client_id=#{CGI.escape(self.config.google_email)}"
|
||||||
uri << "&response_type=code"
|
uri << "&response_type=code"
|
||||||
uri << "&access_type=online"
|
uri << "&access_type=online"
|
||||||
|
|
@ -46,13 +86,166 @@ module JamRuby
|
||||||
uri
|
uri
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# create youtube broadcast
|
||||||
|
def create_broadcast(user, broadcast_options)
|
||||||
|
auth = UserAuthorization.google_auth(user).first
|
||||||
|
if auth.nil? || auth.token.nil?
|
||||||
|
raise JamPermissionError, "No current google token found for user #{user}"
|
||||||
|
end
|
||||||
|
|
||||||
|
broadcast_data = {
|
||||||
|
"snippet" => broadcast_options[:snippet],
|
||||||
|
"status" => broadcast_options[:status],
|
||||||
|
"contentDetails" => broadcast_options[:contentDetails]
|
||||||
|
}
|
||||||
|
|
||||||
|
begin
|
||||||
|
#secrets = Google::APIClient::ClientSecrets.new({"web" => {"access_token" => auth.token, "refresh_token" => auth.refresh_token, "client_id" => @config.google_client_id, "client_secret" => @config.google_secret}})
|
||||||
|
|
||||||
|
|
||||||
|
my_client = create_client
|
||||||
|
|
||||||
|
my_client.authorization = create_authorization(auth, 'https://www.googleapis.com/auth/youtube https://www.googleapis.com/auth/youtube.force-ssl', true)
|
||||||
|
|
||||||
|
puts "BROADCAST DATA: #{broadcast_data}"
|
||||||
|
#y = my_client.discovered_api('youtube', 'v3')
|
||||||
|
response = my_client.execute!(:api_method => youtube.live_broadcasts.insert,
|
||||||
|
:parameters => {:part => 'contentDetails,status,snippet'},
|
||||||
|
:body_object => broadcast_data)
|
||||||
|
|
||||||
|
body = JSON.parse(response.body)
|
||||||
|
puts "CREATE BROADCAST RESPONSE: #{body}"
|
||||||
|
return body
|
||||||
|
rescue Google::APIClient::ClientError => e
|
||||||
|
# ex:
|
||||||
|
=begin
|
||||||
|
ex = {
|
||||||
|
"error": {
|
||||||
|
"errors": [
|
||||||
|
{
|
||||||
|
"domain": "youtube.liveBroadcast",
|
||||||
|
"reason": "liveStreamingNotEnabled",
|
||||||
|
"message": "The user is not enabled for live streaming.",
|
||||||
|
"extendedHelp": "https://www.youtube.com/features"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"code": 403,
|
||||||
|
"message": "The user is not enabled for live streaming."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ex = {
|
||||||
|
"error": {
|
||||||
|
"errors": [
|
||||||
|
{
|
||||||
|
"domain": "youtube.liveBroadcast",
|
||||||
|
"reason": "insufficientLivePermissions",
|
||||||
|
"message": "Request is not authorized",
|
||||||
|
"extendedHelp": "https://developers.google.com/youtube/v3/live/docs/liveBroadcasts/insert#auth_required"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"code": 403,
|
||||||
|
"message": "Request is not authorized"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
=end
|
||||||
|
|
||||||
|
puts e.result.body
|
||||||
|
raise e
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def bind_broadcast(user, broadcast_id, stream_id)
|
||||||
|
auth = UserAuthorization.google_auth(user).first
|
||||||
|
if auth.nil? || auth.token.nil?
|
||||||
|
raise JamPermissionError, "No current google token found for user #{user}"
|
||||||
|
end
|
||||||
|
|
||||||
|
begin
|
||||||
|
my_client = create_client
|
||||||
|
|
||||||
|
my_client.authorization = create_authorization(auth, 'https://www.googleapis.com/auth/youtube https://www.googleapis.com/auth/youtube.force-ssl', true)
|
||||||
|
#y = my_client.discovered_api('youtube', 'v3')
|
||||||
|
response = my_client.execute!(:api_method => youtube.live_broadcasts.bind,
|
||||||
|
:parameters => {:part => 'id,contentDetails,status,snippet', :id => broadcast_id, :streamId => stream_id })
|
||||||
|
|
||||||
|
body = JSON.parse(response.body)
|
||||||
|
puts "BIND RESPONSE: #{body}"
|
||||||
|
return body
|
||||||
|
rescue Google::APIClient::ClientError => e
|
||||||
|
puts e.result.body
|
||||||
|
raise e
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_broadcast(user, broadcast_id)
|
||||||
|
auth = UserAuthorization.google_auth(user).first
|
||||||
|
if auth.nil? || auth.token.nil?
|
||||||
|
raise JamPermissionError, "No current google token found for user #{user}"
|
||||||
|
end
|
||||||
|
|
||||||
|
begin
|
||||||
|
my_client = create_client
|
||||||
|
|
||||||
|
my_client.authorization = create_authorization(auth, 'https://www.googleapis.com/auth/youtube https://www.googleapis.com/auth/youtube.force-ssl', true)
|
||||||
|
#y = my_client.discovered_api('youtube', 'v3')
|
||||||
|
response = my_client.execute!(:api_method => youtube.live_broadcasts.list,
|
||||||
|
:parameters => {:part => 'id,contentDetails,status,snippet', :id => broadcast_id })
|
||||||
|
|
||||||
|
body = JSON.parse(response.body)
|
||||||
|
puts "BIND RESPONSE: #{body}"
|
||||||
|
return body["items"][0] # returns array of items. meh
|
||||||
|
rescue Google::APIClient::ClientError => e
|
||||||
|
puts e.result.body
|
||||||
|
raise e
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_stream(user, stream_options)
|
||||||
|
auth = UserAuthorization.google_auth(user).first
|
||||||
|
if auth.nil? || auth.token.nil?
|
||||||
|
raise JamPermissionError, "No current google token found for user #{user}"
|
||||||
|
end
|
||||||
|
|
||||||
|
broadcast_data = {
|
||||||
|
"snippet" => stream_options[:snippet],
|
||||||
|
"cdn" => stream_options[:cdn],
|
||||||
|
"contentDetails" => stream_options[:contentDetails]
|
||||||
|
}
|
||||||
|
|
||||||
|
begin
|
||||||
|
my_client = create_client
|
||||||
|
|
||||||
|
my_client.authorization = create_authorization(auth, 'https://www.googleapis.com/auth/youtube https://www.googleapis.com/auth/youtube.force-ssl', true)
|
||||||
|
|
||||||
|
puts "STREAM DATA: #{broadcast_data}"
|
||||||
|
#y = my_client.discovered_api('youtube', 'v3')
|
||||||
|
response = my_client.execute!(:api_method => youtube.live_streams.insert,
|
||||||
|
:parameters => {:part => 'id,contentDetails,cdn,status,snippet'},
|
||||||
|
:body_object => broadcast_data)
|
||||||
|
|
||||||
|
body = JSON.parse(response.body)
|
||||||
|
puts "CREATE STREAM RESPONSE: #{body}"
|
||||||
|
return body
|
||||||
|
rescue Google::APIClient::ClientError => e
|
||||||
|
puts e.result.body
|
||||||
|
raise e
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# create youtube broadcast
|
||||||
|
def update_broadcast(user, broadcast_options)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
# Contacts youtube and prepares an upload to youtube. This
|
# Contacts youtube and prepares an upload to youtube. This
|
||||||
# process is somewhat painful, even in ruby, so we do the preparation
|
# process is somewhat painful, even in ruby, so we do the preparation
|
||||||
# and the client does the actual upload using the URL returned:
|
# and the client does the actual upload using the URL returned:
|
||||||
|
|
||||||
# https://developers.google.com/youtube/v3/docs/videos/insert
|
# https://developers.google.com/youtube/v3/docs/videos/insert
|
||||||
# https://developers.google.com/youtube/v3/guides/using_resumable_upload_protocol
|
# https://developers.google.com/youtube/v3/guides/using_resumable_upload_protocol
|
||||||
def sign_youtube_upload(user, filename, length)
|
def sign_youtube_upload(user, filename, length)
|
||||||
raise ArgumentError, "Length is required and should be > 0" if length.to_i.zero?
|
raise ArgumentError, "Length is required and should be > 0" if length.to_i.zero?
|
||||||
|
|
||||||
# Something like this:
|
# Something like this:
|
||||||
|
|
@ -83,32 +276,32 @@ module JamRuby
|
||||||
end
|
end
|
||||||
|
|
||||||
video_data = {
|
video_data = {
|
||||||
"snippet"=> {
|
"snippet" => {
|
||||||
"title"=> filename,
|
"title" => filename,
|
||||||
"description"=> filename,
|
"description" => filename,
|
||||||
"tags"=> ["cool", "video", "more keywords"],
|
"tags" => ["cool", "video", "more keywords"],
|
||||||
"categoryId"=>1
|
"categoryId" => 1
|
||||||
},
|
},
|
||||||
"status"=> {
|
"status" => {
|
||||||
"privacyStatus"=> "public",
|
"privacyStatus" => "public",
|
||||||
"embeddable"=> true,
|
"embeddable" => true,
|
||||||
"license"=> "youtube"
|
"license" => "youtube"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
conn = Faraday.new(:url =>"https://www.googleapis.com",:ssl => {:verify => false}) do |faraday|
|
conn = Faraday.new(:url => "https://www.googleapis.com", :ssl => {:verify => false}) do |faraday|
|
||||||
faraday.request :url_encoded
|
faraday.request :url_encoded
|
||||||
faraday.adapter Faraday.default_adapter
|
faraday.adapter Faraday.default_adapter
|
||||||
end
|
end
|
||||||
|
|
||||||
video_json=video_data.to_json
|
video_json=video_data.to_json
|
||||||
result = conn.post("/upload/youtube/v3/videos?access_token=#{CGI.escape(auth.token)}&uploadType=resumable&part=snippet,status,contentDetails",
|
result = conn.post("/upload/youtube/v3/videos?access_token=#{CGI.escape(auth.token)}&uploadType=resumable&part=snippet,status,contentDetails",
|
||||||
video_json,
|
video_json,
|
||||||
{
|
{
|
||||||
'content-type'=>'application/json;charset=utf-8',
|
'content-type' => 'application/json;charset=utf-8',
|
||||||
'x-Upload-Content-Length'=>"#{length}",
|
'x-Upload-Content-Length' => "#{length}",
|
||||||
'x-upload-content-type'=>"video/*"
|
'x-upload-content-type' => "video/*"
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
# Response should something look like:
|
# Response should something look like:
|
||||||
|
|
@ -119,7 +312,7 @@ module JamRuby
|
||||||
if (result.nil? || result.status!=200 || result.headers['location'].blank?)
|
if (result.nil? || result.status!=200 || result.headers['location'].blank?)
|
||||||
msg = "Failed signing with status=#{result.status} #{result.inspect}: "
|
msg = "Failed signing with status=#{result.status} #{result.inspect}: "
|
||||||
if result.body.present? && result.body.length > 2
|
if result.body.present? && result.body.length > 2
|
||||||
msg << result.body.inspect# JSON.parse(result.body).inspect
|
msg << result.body.inspect # JSON.parse(result.body).inspect
|
||||||
end
|
end
|
||||||
|
|
||||||
# TODO: how to test for this:
|
# TODO: how to test for this:
|
||||||
|
|
@ -130,11 +323,11 @@ module JamRuby
|
||||||
else
|
else
|
||||||
# This has everything one needs to start the upload to youtube:
|
# This has everything one needs to start the upload to youtube:
|
||||||
{
|
{
|
||||||
"method" => "PUT",
|
"method" => "PUT",
|
||||||
"url" => result.headers['location'],
|
"url" => result.headers['location'],
|
||||||
"Authorization" => "Bearer #{auth.token}",
|
"Authorization" => "Bearer #{auth.token}",
|
||||||
"Content-Length" => length,
|
"Content-Length" => length,
|
||||||
"Content-Type" => "video/*"
|
"Content-Type" => "video/*"
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -151,20 +344,20 @@ module JamRuby
|
||||||
# Content-Length: 0
|
# Content-Length: 0
|
||||||
# Content-Range: bytes */CONTENT_LENGTH
|
# Content-Range: bytes */CONTENT_LENGTH
|
||||||
RestClient.put(upload_url, nil, {
|
RestClient.put(upload_url, nil, {
|
||||||
'Authorization' => "Bearer #{auth.token}",
|
'Authorization' => "Bearer #{auth.token}",
|
||||||
'Content-Length'=> "0",
|
'Content-Length' => "0",
|
||||||
'Content-Range' => "bytes */#{length}"
|
'Content-Range' => "bytes */#{length}"
|
||||||
}) do |response, request, result|
|
}) do |response, request, result|
|
||||||
# Result looks like this:
|
# Result looks like this:
|
||||||
# 308 Resume Incomplete
|
# 308 Resume Incomplete
|
||||||
# Content-Length: 0
|
# Content-Length: 0
|
||||||
# Range: bytes=0-999999
|
# Range: bytes=0-999999
|
||||||
case(response.code)
|
case (response.code)
|
||||||
when 200..207
|
when 200..207
|
||||||
result_hash = {
|
result_hash = {
|
||||||
"offset" => 0,
|
"offset" => 0,
|
||||||
"length" => length,
|
"length" => length,
|
||||||
"status" => response.code
|
"status" => response.code
|
||||||
}
|
}
|
||||||
when 308
|
when 308
|
||||||
range_str = response.headers['Range']
|
range_str = response.headers['Range']
|
||||||
|
|
@ -174,9 +367,9 @@ module JamRuby
|
||||||
range = range_str.split("-")
|
range = range_str.split("-")
|
||||||
end
|
end
|
||||||
result_hash = {
|
result_hash = {
|
||||||
"offset" => range.first.to_i,
|
"offset" => range.first.to_i,
|
||||||
"length" => range.last.to_i,
|
"length" => range.last.to_i,
|
||||||
"status" => response.code
|
"status" => response.code
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
raise "Unexpected status from youtube: [#{response.code}] with headers: #{response.headers.inspect}"
|
raise "Unexpected status from youtube: [#{response.code}] with headers: #{response.headers.inspect}"
|
||||||
|
|
@ -209,13 +402,13 @@ module JamRuby
|
||||||
else
|
else
|
||||||
Rails.logger.info "Login with: #{recaptcha_response}"
|
Rails.logger.info "Login with: #{recaptcha_response}"
|
||||||
RestClient.get("https://www.google.com/recaptcha/api/siteverify",
|
RestClient.get("https://www.google.com/recaptcha/api/siteverify",
|
||||||
params: {
|
params: {
|
||||||
secret: Rails.application.config.recaptcha_private_key,
|
secret: Rails.application.config.recaptcha_private_key,
|
||||||
response: recaptcha_response
|
response: recaptcha_response
|
||||||
}
|
}
|
||||||
) do |response, request, result|
|
) do |response, request, result|
|
||||||
Rails.logger.info "response: #{response.inspect}"
|
Rails.logger.info "response: #{response.inspect}"
|
||||||
case(response.code)
|
case (response.code)
|
||||||
when 200..207
|
when 200..207
|
||||||
json = JSON.parse(response.to_str)
|
json = JSON.parse(response.to_str)
|
||||||
if json['success']
|
if json['success']
|
||||||
|
|
@ -229,7 +422,9 @@ module JamRuby
|
||||||
end #do
|
end #do
|
||||||
end # if
|
end # if
|
||||||
success
|
success
|
||||||
end #def
|
end
|
||||||
|
|
||||||
|
#def
|
||||||
|
|
||||||
# This will also sign in and prompt for login as necessary;
|
# This will also sign in and prompt for login as necessary;
|
||||||
# currently requires the server to be running at localhost:3000
|
# currently requires the server to be running at localhost:3000
|
||||||
|
|
@ -237,15 +432,16 @@ module JamRuby
|
||||||
config = Rails.application.config
|
config = Rails.application.config
|
||||||
|
|
||||||
self.client = Google::APIClient.new(
|
self.client = Google::APIClient.new(
|
||||||
:application_name => 'JamKazam',
|
:application_name => 'JamKazam',
|
||||||
:application_version => '1.0.0'
|
:application_version => '1.0.0'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
raise "SIGNIN FLOW!!"
|
||||||
flow = Google::APIClient::InstalledAppFlow.new(
|
flow = Google::APIClient::InstalledAppFlow.new(
|
||||||
:client_id => config.google_client_id,
|
:client_id => config.google_client_id,
|
||||||
:client_secret => config.google_secret,
|
:client_secret => config.google_secret,
|
||||||
:redirect_uri=>redirect_uri,
|
:redirect_uri => redirect_uri,
|
||||||
:scope => 'email profile'
|
:scope => 'email profile https://www.googleapis.com/auth/youtube https://www.googleapis.com/auth/youtube.upload'
|
||||||
)
|
)
|
||||||
|
|
||||||
self.client.authorization = flow.authorize
|
self.client.authorization = flow.authorize
|
||||||
|
|
@ -254,9 +450,9 @@ module JamRuby
|
||||||
# Must manually confirm to obtain refresh token:
|
# Must manually confirm to obtain refresh token:
|
||||||
def get_refresh_token
|
def get_refresh_token
|
||||||
config = Rails.application.config
|
config = Rails.application.config
|
||||||
conn = Faraday.new(:url => 'https://accounts.google.com',:ssl => {:verify => false}) do |faraday|
|
conn = Faraday.new(:url => 'https://accounts.google.com', :ssl => {:verify => false}) do |faraday|
|
||||||
faraday.request :url_encoded
|
faraday.request :url_encoded
|
||||||
faraday.adapter Faraday.default_adapter
|
faraday.adapter Faraday.default_adapter
|
||||||
end
|
end
|
||||||
|
|
||||||
wait_for_callback do |refresh_token|
|
wait_for_callback do |refresh_token|
|
||||||
|
|
@ -264,21 +460,21 @@ module JamRuby
|
||||||
end
|
end
|
||||||
|
|
||||||
result = conn.get '/o/oauth2/auth', {
|
result = conn.get '/o/oauth2/auth', {
|
||||||
'scope'=>'email profile',
|
'scope' => 'email profile https://www.googleapis.com/auth/youtube https://www.googleapis.com/auth/youtube.upload',
|
||||||
'client_id'=>config.google_client_id,
|
'client_id' => config.google_client_id,
|
||||||
'response_type'=>"code",
|
'response_type' => "code",
|
||||||
'access_type'=>"offline",
|
'access_type' => "offline",
|
||||||
'redirect_uri'=>redirect_uri
|
'redirect_uri' => redirect_uri
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_access_token(refresh_token)
|
def get_access_token(refresh_token)
|
||||||
refresh_token = "4/g9uZ8S4lq2Bj1J8PPIkgOFKhTKmCHSmRe68iHA75hRg.gj8Nt5bpVYQdPm8kb2vw2M23tnRnkgI"
|
refresh_token = "4/g9uZ8S4lq2Bj1J8PPIkgOFKhTKmCHSmRe68iHA75hRg.gj8Nt5bpVYQdPm8kb2vw2M23tnRnkgI"
|
||||||
|
|
||||||
config = Rails.application.config
|
config = Rails.application.config
|
||||||
conn = Faraday.new(:url => 'https://accounts.google.com',:ssl => {:verify => false}) do |faraday|
|
conn = Faraday.new(:url => 'https://accounts.google.com', :ssl => {:verify => false}) do |faraday|
|
||||||
faraday.request :url_encoded
|
faraday.request :url_encoded
|
||||||
faraday.adapter Faraday.default_adapter
|
faraday.adapter Faraday.default_adapter
|
||||||
end
|
end
|
||||||
|
|
||||||
wait_for_callback do |access_token|
|
wait_for_callback do |access_token|
|
||||||
|
|
@ -286,13 +482,13 @@ module JamRuby
|
||||||
end
|
end
|
||||||
|
|
||||||
result = conn.post '/o/oauth2/token', nil, {
|
result = conn.post '/o/oauth2/token', nil, {
|
||||||
'scope'=>'email profile',
|
'scope' => 'email profile https://www.googleapis.com/auth/youtube https://www.googleapis.com/auth/youtube.upload',
|
||||||
'client_id'=>config.google_client_id,
|
'client_id' => config.google_client_id,
|
||||||
'client_secret'=>config.google_secret,
|
'client_secret' => config.google_secret,
|
||||||
'refresh_token'=>refresh_token,
|
'refresh_token' => refresh_token,
|
||||||
'grant_type'=>"refresh_token",
|
'grant_type' => "refresh_token",
|
||||||
'redirect_uri'=>redirect_uri
|
'redirect_uri' => redirect_uri
|
||||||
}
|
}
|
||||||
|
|
||||||
Rails.logger.info("REsult: #{result.inspect}\n\n")
|
Rails.logger.info("REsult: #{result.inspect}\n\n")
|
||||||
end
|
end
|
||||||
|
|
@ -320,9 +516,9 @@ module JamRuby
|
||||||
|
|
||||||
response = "#{status}\n"
|
response = "#{status}\n"
|
||||||
self.socket.print "HTTP/1.1 200 OK\r\n" +
|
self.socket.print "HTTP/1.1 200 OK\r\n" +
|
||||||
"Content-Type: text/plain\r\n" +
|
"Content-Type: text/plain\r\n" +
|
||||||
"Content-Length: #{response.bytesize}\r\n" +
|
"Content-Length: #{response.bytesize}\r\n" +
|
||||||
"Connection: close\r\n"
|
"Connection: close\r\n"
|
||||||
|
|
||||||
self.socket.print "\r\n"
|
self.socket.print "\r\n"
|
||||||
self.socket.print response
|
self.socket.print response
|
||||||
|
|
@ -339,17 +535,17 @@ module JamRuby
|
||||||
|
|
||||||
def exchange_for_token(access_code)
|
def exchange_for_token(access_code)
|
||||||
Rails.logger.info("Exchanging token for code: [#{access_code}]")
|
Rails.logger.info("Exchanging token for code: [#{access_code}]")
|
||||||
conn = Faraday.new(:url =>"https://accounts.google.com",:ssl => {:verify => false}) do |faraday|
|
conn = Faraday.new(:url => "https://accounts.google.com", :ssl => {:verify => false}) do |faraday|
|
||||||
faraday.request :url_encoded
|
faraday.request :url_encoded
|
||||||
faraday.adapter Faraday.default_adapter
|
faraday.adapter Faraday.default_adapter
|
||||||
end
|
end
|
||||||
|
|
||||||
exchange_parms={
|
exchange_parms={
|
||||||
'grant_type'=>'authorization_code',
|
'grant_type' => 'authorization_code',
|
||||||
'code'=>(access_code),
|
'code' => (access_code),
|
||||||
'client_id'=>(config.google_email),
|
'client_id' => (config.google_email),
|
||||||
'client_secret'=>(config.google_secret),
|
'client_secret' => (config.google_secret),
|
||||||
'redirect_uri'=>(redirect_uri),
|
'redirect_uri' => (redirect_uri),
|
||||||
}
|
}
|
||||||
|
|
||||||
result = conn.post('/o/oauth2/token', exchange_parms)
|
result = conn.post('/o/oauth2/token', exchange_parms)
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,14 @@
|
||||||
=begin
|
Rails.logger = Logger.new(STDOUT)
|
||||||
require 'google/api_client'
|
require Rails.root.join('lib', 'google_client')
|
||||||
|
|
||||||
namespace :google do
|
namespace :google do
|
||||||
|
task create_broadcast: :environment do |task, args|
|
||||||
|
google_client = JamRuby::GoogleClient.new
|
||||||
|
music_session = MusicSession.first
|
||||||
|
user = User.find_by_email('seth@jamkazam.com')
|
||||||
|
|
||||||
task :youtube do |task, args|
|
broadcast = music_session.create_stream(google_client, user, nil)
|
||||||
client = Google::APIClient.new
|
|
||||||
yt = client.discovered_api('youtube', 'v3')
|
puts broadcast.inspect
|
||||||
# google-api oauth-2-login --client-id='785931784279-gd0g8on6sc0tuesj7cu763pitaiv2la8.apps.googleusercontent.com' --client-secret='UwzIcvtErv9c2-GIsNfIo7bA' --scope="https://www.googleapis.com/auth/plus.me"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
=end
|
|
||||||
|
|
@ -35,6 +35,12 @@ namespace :jam_tracks do
|
||||||
JamTrackImporter.dry_run
|
JamTrackImporter.dry_run
|
||||||
end
|
end
|
||||||
|
|
||||||
|
task create_clevie: :environment do |task, args|
|
||||||
|
licensor = JamTrackLicensor.new()
|
||||||
|
licensor.name = 'Steely & Clevie'
|
||||||
|
licensor.slug = 'steely-and-clevie'
|
||||||
|
licensor.save!
|
||||||
|
end
|
||||||
task tency_dry_run: :environment do |task, args|
|
task tency_dry_run: :environment do |task, args|
|
||||||
JamTrackImporter.storage_format = 'Tency'
|
JamTrackImporter.storage_format = 'Tency'
|
||||||
JamTrackImporter.dry_run
|
JamTrackImporter.dry_run
|
||||||
|
|
@ -50,6 +56,11 @@ namespace :jam_tracks do
|
||||||
JamTrackImporter.dry_run
|
JamTrackImporter.dry_run
|
||||||
end
|
end
|
||||||
|
|
||||||
|
task clevie_dry_run: :environment do |task, args|
|
||||||
|
JamTrackImporter.storage_format = 'Clevie'
|
||||||
|
JamTrackImporter.dry_run
|
||||||
|
end
|
||||||
|
|
||||||
task paris_create_masters: :environment do |task, args|
|
task paris_create_masters: :environment do |task, args|
|
||||||
JamTrackImporter.storage_format = 'Paris'
|
JamTrackImporter.storage_format = 'Paris'
|
||||||
JamTrackImporter.create_masters
|
JamTrackImporter.create_masters
|
||||||
|
|
@ -87,6 +98,18 @@ namespace :jam_tracks do
|
||||||
JamTrackImporter.create_master(path)
|
JamTrackImporter.create_master(path)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
task clevie_create_master: :environment do |task, args|
|
||||||
|
JamTrackImporter.storage_format = 'Clevie'
|
||||||
|
|
||||||
|
path = ENV['TRACK_PATH']
|
||||||
|
|
||||||
|
if !path
|
||||||
|
puts "TRACK_PATH must be set to something like audio/AC DC/Back in Black or mapped/50 Cent - In Da Club - 12401"
|
||||||
|
exit(1)
|
||||||
|
end
|
||||||
|
|
||||||
|
JamTrackImporter.create_master(path)
|
||||||
|
end
|
||||||
|
|
||||||
task tency_delta: :environment do |task, args|
|
task tency_delta: :environment do |task, args|
|
||||||
JamTrackImporter.storage_format = 'Tency'
|
JamTrackImporter.storage_format = 'Tency'
|
||||||
|
|
@ -211,6 +234,11 @@ namespace :jam_tracks do
|
||||||
JamTrackImporter.synchronize_all(skip_audio_upload: false)
|
JamTrackImporter.synchronize_all(skip_audio_upload: false)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
task sync_clevie: :environment do |task, args|
|
||||||
|
JamTrackImporter.storage_format = 'Clevie'
|
||||||
|
JamTrackImporter.synchronize_all(skip_audio_upload: false)
|
||||||
|
end
|
||||||
|
|
||||||
task tency_dups: :environment do |task, args|
|
task tency_dups: :environment do |task, args|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue