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>
87 lines
3.4 KiB
Ruby
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
|