module Youtube class BroadcastService class Error < StandardError; end def initialize(team) @team = team @credential = team.youtube_credential end def create_broadcast!(title:, privacy_status: "unlisted", scheduled_at: nil) return mock_broadcast if @credential.blank? || missing_oauth_config? client = authorized_client broadcast = Google::Apis::YoutubeV3::LiveBroadcast.new( snippet: Google::Apis::YoutubeV3::LiveBroadcastSnippet.new( title: title, scheduled_start_time: scheduled_at&.iso8601 ), status: Google::Apis::YoutubeV3::LiveBroadcastStatus.new( privacy_status: privacy_status, self_declared_made_for_kids: false ), content_details: Google::Apis::YoutubeV3::LiveBroadcastContentDetails.new( enable_auto_start: true, enable_auto_stop: true ) ) result = client.insert_live_broadcast("snippet,status,contentDetails", broadcast) stream = Google::Apis::YoutubeV3::LiveStream.new( snippet: Google::Apis::YoutubeV3::LiveStreamSnippet.new(title: "#{title} stream"), cdn: Google::Apis::YoutubeV3::CdnSettings.new( frame_rate: "30fps", ingestion_type: "rtmp", resolution: "720p" ) ) stream_result = client.insert_live_stream("snippet,cdn", stream) client.bind_live_broadcast(result.id, "id,contentDetails", stream_result.id) { broadcast_id: result.id, stream_id: stream_result.id, stream_key: stream_result.cdn.ingestion_info.stream_name, rtmp_url: stream_result.cdn.ingestion_info.ingestion_address } rescue Google::Apis::Error => e raise Error, e.message end def complete_broadcast!(broadcast_id) return if @credential.blank? || missing_oauth_config? client = authorized_client client.transition_live_broadcast(broadcast_id, "complete") rescue Google::Apis::Error nil end def viewer_count(broadcast_id) return 0 if @credential.blank? || missing_oauth_config? client = authorized_client resp = client.list_live_broadcasts("statistics", id: broadcast_id) resp.items&.first&.statistics&.concurrent_viewers.to_i rescue Google::Apis::Error 0 end private def mock_broadcast { broadcast_id: "mock_#{SecureRandom.hex(8)}", stream_id: "mock_stream", stream_key: ENV.fetch("YOUTUBE_MOCK_STREAM_KEY", "mock-stream-key"), rtmp_url: "rtmp://a.rtmp.youtube.com/live2" } end def missing_oauth_config? ENV["YOUTUBE_CLIENT_ID"].blank? end def authorized_client OauthRefresh.new(@credential).apply!(Google::Apis::YoutubeV3::YouTubeService.new) end end end