module Sessions class Create def self.normalize_privacy(value) value.to_s == "public" ? "public" : "unlisted" end def initialize(user:, match:, params:) @user = user @match = match @params = params end def call platform = @params[:platform].presence || "matchlivetv" ent = @match.team.entitlements ent.assert_can_stream_on!(platform) ent.assert_concurrent_stream! session = StreamSession.new( match: @match, user: @user, platform: platform, privacy_status: Sessions::Create.normalize_privacy(@params[:privacy_status]), quality_preset: @params[:quality_preset] || "720p_30_2.5mbps", target_bitrate: @params[:target_bitrate] || 2_500_000, target_fps: @params[:target_fps] || 30, status: "idle" ) if session.platform == "youtube" youtube_channel = @params[:youtube_channel].presence assert_youtube_channel!(youtube_channel) attach_youtube_broadcast!(session, youtube_channel: youtube_channel) end StreamSession.transaction do session.save! session.create_score_state! mtx = Mediamtx::Client.new mtx.create_path(session) mtx.create_overlay_path(session) start_overlay_relay(session) start_youtube_relay(session) log_event(session, "pairing", { created: true, platform: session.platform }) end session end private def assert_youtube_channel!(youtube_channel) resolver = Youtube::CredentialResolver.new(@match.team, channel: youtube_channel) if resolver.resolve.blank? raise Teams::EntitlementError.new( "Canale YouTube selezionato non disponibile", code: "youtube_channel_unavailable" ) end end def attach_youtube_broadcast!(session, youtube_channel: nil) yt = Youtube::BroadcastService.new(session.match.team, youtube_channel: youtube_channel) title = "#{session.match.team.name} vs #{session.match.opponent_name}" broadcast = yt.create_broadcast!( title: title, privacy_status: session.privacy_status, scheduled_at: session.match.scheduled_at ) session.youtube_broadcast_id = broadcast[:broadcast_id] session.youtube_stream_id = broadcast[:stream_id] session.stream_key = broadcast[:stream_key] session.rtmp_url = broadcast[:rtmp_url] end def start_overlay_relay(session) Streams::OverlayRelay.start(session) rescue Streams::OverlayRelay::Error => e Rails.logger.warn("[Sessions::Create] Overlay relay: #{e.message}") end def start_youtube_relay(session) return unless session.platform == "youtube" Streams::YoutubeRelay.start(session) rescue Streams::YoutubeRelay::Error => e Rails.logger.warn("[Sessions::Create] YouTube relay: #{e.message}") end def log_event(session, type, metadata) session.stream_events.create!(event_type: type, metadata: metadata, occurred_at: Time.current) end end end