Non propone più il link MLTV per sessioni YouTube; la pagina /live reindirizza a YouTube; il relay verso YouTube si riavvia al connect. Co-authored-by: Cursor <cursoragent@cursor.com>
178 lines
5.8 KiB
Ruby
178 lines
5.8 KiB
Ruby
module Api
|
|
module V1
|
|
class StreamSessionsController < BaseController
|
|
before_action :set_session, except: :create
|
|
|
|
def create
|
|
team_ids = current_user.streamable_teams.map(&:id)
|
|
match = Match.where(team_id: team_ids).find(params[:match_id])
|
|
session = Sessions::Create.new(user: current_user, match: match, params: session_params).call
|
|
render json: session_json(session), status: :created
|
|
end
|
|
|
|
def show
|
|
render json: session_json(@session, detail: true)
|
|
end
|
|
|
|
def start
|
|
Sessions::Start.new(@session).call
|
|
render json: session_json(@session)
|
|
end
|
|
|
|
def stop
|
|
Sessions::Stop.new(@session).call
|
|
render json: session_json(@session)
|
|
end
|
|
|
|
def pause
|
|
Sessions::Pause.new(@session).call
|
|
render json: session_json(@session)
|
|
end
|
|
|
|
def resume
|
|
Sessions::Resume.new(@session).call
|
|
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) }
|
|
end
|
|
|
|
def telemetry
|
|
role = params.require(:device_role)
|
|
state = @session.device_states.find_or_initialize_by(device_role: role)
|
|
state.update!(
|
|
battery_level: params[:battery_level],
|
|
network_type: params[:network_type],
|
|
signal_strength: params[:signal_strength],
|
|
current_bitrate: params[:current_bitrate],
|
|
target_bitrate: params[:target_bitrate],
|
|
fps: params[:fps],
|
|
last_seen_at: Time.current
|
|
)
|
|
SessionChannel.broadcast_message(@session, state.as_cable_payload)
|
|
head :no_content
|
|
end
|
|
|
|
def pairing_token
|
|
token = SecureRandom.urlsafe_base64(24)
|
|
@session.update!(
|
|
pairing_token_digest: Digest::SHA256.hexdigest(token),
|
|
pairing_token_expires_at: 15.minutes.from_now
|
|
)
|
|
render json: {
|
|
pairing_token: token,
|
|
expires_at: @session.pairing_token_expires_at,
|
|
qr_payload: {
|
|
session_id: @session.id,
|
|
pairing_token: token,
|
|
api_url: request.base_url
|
|
}
|
|
}
|
|
end
|
|
|
|
def regia_link
|
|
access = Sessions::RegiaAccess.new(@session)
|
|
token = access.issue_token!
|
|
render json: {
|
|
regia_url: access.url(token),
|
|
expires_at: @session.regia_token_expires_at
|
|
}
|
|
end
|
|
|
|
def claim_pairing
|
|
token = params.require(:pairing_token)
|
|
digest = Digest::SHA256.hexdigest(token)
|
|
unless @session.pairing_token_digest == digest &&
|
|
@session.pairing_token_expires_at&.future?
|
|
return render json: { error: "Invalid or expired token" }, status: :unauthorized
|
|
end
|
|
|
|
@session.device_states.find_or_create_by!(device_role: params[:device_role] || "controller")
|
|
render json: session_json(@session)
|
|
end
|
|
|
|
def network_test
|
|
@session.stream_events.create!(
|
|
event_type: "network_test",
|
|
metadata: params.permit(:download_mbps, :upload_mbps, :latency_ms, :network_type).to_h,
|
|
occurred_at: Time.current
|
|
)
|
|
ready = params[:upload_mbps].to_f >= (@session.target_bitrate / 1_000_000.0 * 0.8)
|
|
render json: { ready: ready, target_upload_mbps: @session.target_bitrate / 1_000_000.0 }
|
|
end
|
|
|
|
def youtube_stats
|
|
count = if @session.platform == "youtube" && @session.youtube_broadcast_id.present?
|
|
Youtube::BroadcastService.new(@session.match.team)
|
|
.viewer_count(@session.youtube_broadcast_id)
|
|
else
|
|
0
|
|
end
|
|
render json: { concurrent_viewers: count, live: @session.live? }
|
|
end
|
|
|
|
private
|
|
|
|
def set_session
|
|
team_ids = current_user.streamable_teams.map(&:id)
|
|
@session = StreamSession.joins(:match)
|
|
.where(matches: { team_id: team_ids })
|
|
.find(params[:id])
|
|
end
|
|
|
|
def session_params
|
|
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,
|
|
match_id: session.match_id,
|
|
status: session.status,
|
|
platform: session.platform,
|
|
rtmp_ingest_url: session.rtmp_ingest_url,
|
|
hls_playback_url: session.hls_playback_url,
|
|
watch_page_url: session.matchlivetv_platform? ? session.watch_page_url : nil,
|
|
share_url: session.share_url,
|
|
youtube_watch_url: session.youtube_watch_url,
|
|
youtube_broadcast_id: session.youtube_broadcast_id,
|
|
youtube_ready: session.youtube_ready?,
|
|
privacy_status: session.privacy_status,
|
|
quality_preset: session.quality_preset,
|
|
target_bitrate: session.target_bitrate,
|
|
started_at: session.started_at,
|
|
disconnection_count: session.disconnection_count
|
|
}
|
|
if detail
|
|
data[:score] = session.score_state&.as_cable_payload
|
|
data[:devices] = session.device_states.map(&:as_cable_payload)
|
|
end
|
|
data
|
|
end
|
|
|
|
def event_json(event)
|
|
{
|
|
id: event.id,
|
|
event_type: event.event_type,
|
|
metadata: event.metadata,
|
|
occurred_at: event.occurred_at
|
|
}
|
|
end
|
|
end
|
|
end
|
|
end
|