Files

100 lines
3.8 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)
tournaments = Tournament.listed_on_live.with_attached_logo_file.includes(:club).search_public(@query)
tournaments = tournaments.where(club_id: @club.id) if @club
@public_tournaments = tournaments.order(starts_on: :desc, name: :asc).limit(12)
@online_paths = fetch_online_paths
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)
@cover_poster_url = Streams::CoverResolver.new(@match).effective_cover_url
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
private
def fetch_online_paths
Mediamtx::Client.new.online_path_names
rescue Mediamtx::Client::Error, Errno::ECONNREFUSED, SocketError
[]
end
end
end