Files
MatchLiveTv/backend/app/services/sessions/create.rb
Emiliano Frascaro ab9cb02083 Aggiunge overlay server-side burn-in e stabilizza diretta live.
Tabellone, badge e brand sono ricodificati nel flusso _air via OverlayRelay;
sync punteggio HTTP, volume condiviso rails/sidekiq, qualità 720p migliorata
e badge CONNECTING in ripresa da pausa.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-03 23:55:17 +02:00

96 lines
3.0 KiB
Ruby

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