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>
This commit is contained in:
@@ -34,6 +34,11 @@ module Api
|
||||
render json: session_json(@session)
|
||||
end
|
||||
|
||||
def score
|
||||
Scoring::SyncState.new(session: @session, payload: score_sync_params).call
|
||||
render json: session_json(@session, detail: true)
|
||||
end
|
||||
|
||||
def events
|
||||
events = @session.stream_events.recent.limit(100)
|
||||
render json: events.map { |e| event_json(e) }
|
||||
@@ -126,6 +131,13 @@ module Api
|
||||
params.permit(:platform, :privacy_status, :quality_preset, :target_bitrate, :target_fps, :youtube_channel)
|
||||
end
|
||||
|
||||
def score_sync_params
|
||||
params.permit(
|
||||
:home_sets, :away_sets, :home_points, :away_points, :current_set,
|
||||
set_partials: %i[set home away]
|
||||
)
|
||||
end
|
||||
|
||||
def session_json(session, detail: false)
|
||||
data = {
|
||||
id: session.id,
|
||||
|
||||
34
backend/app/controllers/concerns/mediamtx_playback.rb
Normal file
34
backend/app/controllers/concerns/mediamtx_playback.rb
Normal file
@@ -0,0 +1,34 @@
|
||||
module MediamtxPlayback
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
private
|
||||
|
||||
def mediamtx_paths_index
|
||||
@mediamtx_paths_index ||= Mediamtx::Client.new.list_paths.index_by { |i| i["name"] }
|
||||
end
|
||||
|
||||
def mediamtx_path_info(session, path_name: mediamtx_playback_path_name(session))
|
||||
mediamtx_paths_index[path_name]
|
||||
end
|
||||
|
||||
def mediamtx_playback_path_name(session)
|
||||
session.effective_hls_path_name
|
||||
end
|
||||
|
||||
# Player HLS: path _air con overlay quando il relay è attivo.
|
||||
def mediamtx_stream_playable?(session)
|
||||
return false if session.terminal?
|
||||
|
||||
mediamtx_path_has_output?(session)
|
||||
end
|
||||
|
||||
def mediamtx_path_has_output?(session)
|
||||
info = mediamtx_path_info(session)
|
||||
info && (info["ready"] || info["available"] || info["online"])
|
||||
end
|
||||
|
||||
def mediamtx_publisher_online?(session)
|
||||
info = mediamtx_paths_index[session.mediamtx_path_name]
|
||||
info && info["online"]
|
||||
end
|
||||
end
|
||||
@@ -1,5 +1,7 @@
|
||||
module Public
|
||||
class LiveController < SiteBaseController
|
||||
include MediamtxPlayback
|
||||
|
||||
layout "marketing_live"
|
||||
|
||||
ACTIVE_STATUSES = %w[live connecting reconnecting].freeze
|
||||
@@ -40,31 +42,41 @@ module Public
|
||||
|
||||
def show
|
||||
@session = StreamSession.includes(match: { team: :club }).find(params[:id])
|
||||
@session = Mediamtx::PublisherSync.new(@session).call unless @session.terminal?
|
||||
@match = @session.match
|
||||
@stream_closed = @session.terminal?
|
||||
@on_air = !@stream_closed && mediamtx_online?(@session)
|
||||
@on_air = !@stream_closed && mediamtx_stream_playable?(@session)
|
||||
@publisher_online = !@stream_closed && mediamtx_publisher_online?(@session)
|
||||
end
|
||||
|
||||
def status
|
||||
# Mai cache: il tabellone deve restare allineato con l'app (poll ogni ~1,5s).
|
||||
response.headers["Cache-Control"] = "no-store, no-cache, must-revalidate"
|
||||
response.headers["Pragma"] = "no-cache"
|
||||
|
||||
session = StreamSession.includes(match: { team: :club }).find(params[:id])
|
||||
session = Mediamtx::PublisherSync.new(session).call unless session.terminal?
|
||||
closed = session.terminal?
|
||||
publisher_online = !closed && mediamtx_publisher_online?(session)
|
||||
playable = !closed && mediamtx_stream_playable?(session)
|
||||
render json: {
|
||||
status: session.status,
|
||||
paused: session.paused?,
|
||||
stream_closed: closed,
|
||||
live: !closed && (session.live? || mediamtx_online?(session)),
|
||||
on_air: !closed && mediamtx_online?(session),
|
||||
live: !closed && (
|
||||
session.live? || session.paused? || session.connecting? || session.reconnecting? ||
|
||||
mediamtx_publisher_online?(session)
|
||||
),
|
||||
on_air: playable,
|
||||
publisher_online: publisher_online,
|
||||
awaiting_signal: !closed && !mediamtx_path_has_output?(session),
|
||||
showing_cover: !closed && mediamtx_path_has_output?(session) &&
|
||||
(session.paused? || !mediamtx_publisher_online?(session)),
|
||||
ended_at: session.ended_at,
|
||||
home_name: session.match.team.name,
|
||||
away_name: session.match.opponent_name,
|
||||
score: session.score_state&.as_cable_payload
|
||||
}
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def mediamtx_online?(session)
|
||||
@online_paths_cache ||= Mediamtx::Client.new.online_path_names
|
||||
@online_paths_cache.include?(session.mediamtx_path_name)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
module Public
|
||||
class RegiaController < SiteBaseController
|
||||
include Public::LiveHelper
|
||||
include MediamtxPlayback
|
||||
|
||||
layout "regia"
|
||||
|
||||
@@ -17,7 +18,7 @@ module Public
|
||||
)
|
||||
@rules = Scoring::Rules.from_match(@match)
|
||||
@stream_closed = @session.terminal?
|
||||
@on_air = !@stream_closed && mediamtx_online?(@session)
|
||||
@on_air = !@stream_closed && mediamtx_stream_playable?(@session)
|
||||
@share_url = request.original_url
|
||||
@share_title = "Regia — #{@team.name} vs #{@match.opponent_name}"
|
||||
end
|
||||
@@ -61,12 +62,14 @@ module Public
|
||||
def status_payload
|
||||
score = @session.score_state
|
||||
closed = @session.terminal?
|
||||
playable = !closed && mediamtx_stream_playable?(@session)
|
||||
{
|
||||
status: @session.status,
|
||||
paused: @session.paused?,
|
||||
stream_closed: closed,
|
||||
live: !closed && (@session.live? || mediamtx_online?(@session)),
|
||||
on_air: !closed && mediamtx_online?(@session),
|
||||
live: !closed && (@session.live? || @session.paused? || mediamtx_publisher_online?(@session)),
|
||||
on_air: playable,
|
||||
publisher_online: !closed && mediamtx_publisher_online?(@session),
|
||||
ended_at: @session.ended_at,
|
||||
home_name: @session.match.team.name,
|
||||
away_name: @session.match.opponent_name,
|
||||
@@ -74,10 +77,5 @@ module Public
|
||||
score: score&.as_cable_payload
|
||||
}
|
||||
end
|
||||
|
||||
def mediamtx_online?(session)
|
||||
@online_paths_cache ||= Mediamtx::Client.new.online_path_names
|
||||
@online_paths_cache.include?(session.mediamtx_path_name)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user