Files
MatchLiveTv/backend/app/controllers/public/live_controller.rb
T
eminuxandCursor 854738b46d Stabilizza live YouTube/RTMP e fix crash rotazione mobile.
Pipeline YouTube con relay, overlay e publisher sync lato backend; fix GL pauseGlDuringRotation su Android per evitare crash in rotazione durante lo streaming Flutter.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-06 15:30:55 +02:00

87 lines
3.4 KiB
Ruby

module Public
class LiveController < SiteBaseController
include MediamtxPlayback
layout "marketing_live"
ACTIVE_STATUSES = %w[live connecting reconnecting].freeze
def index
@query = params[:q].to_s.strip
@club = Club.find_by(id: params[:club_id]) if params[:club_id].present?
team_ids = @club&.teams&.pluck(:id)
sessions = StreamSession
.broadcasting
.publicly_listed
.where(platform: "matchlivetv")
.includes(:score_state, match: { team: :club })
sessions = sessions.joins(:match).where(matches: { team_id: team_ids }) if team_ids.present?
@sessions = sessions
.search_by_team_or_opponent(@query)
.order(Arel.sql("started_at DESC NULLS LAST"), created_at: :desc)
# Solo dirette già in onda: le partite «programmate» restano visibili anche se c’è sessione idle.
broadcasting_match_ids = StreamSession.broadcasting.select(:match_id)
upcoming = Match.scheduled_for_live.includes(team: :club)
upcoming = upcoming.where(team_id: team_ids) if team_ids.present?
@upcoming_matches = upcoming
.search_teams_or_opponents(@query)
.where.not(id: broadcasting_match_ids)
.order(scheduled_at: :asc)
.limit(50)
@online_paths = Mediamtx::Client.new.online_path_names
return unless logged_in? && @club
@schedulable_teams = current_user.schedulable_teams_for(@club)
@can_schedule_match = @schedulable_teams.any?
end
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_stream_playable?(@session) ||
@session.status.in?(%w[connecting live reconnecting paused])
)
@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? || session.paused? || session.connecting? || session.reconnecting? ||
mediamtx_publisher_online?(session)
),
on_air: playable || (!closed && session.status.in?(%w[connecting live reconnecting paused])),
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
end
end