Aggiunge replay YouTube temporaneo, pull registrazioni dai CPX e snapshot ingest in admin.
Così overflow Hetzner e VOD YouTube restano in archivio dopo lo spegnimento del nodo, e la colonna ingest non si svuota. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -60,4 +60,31 @@ RSpec.describe "Admin sessions index", type: :request do
|
||||
expect(response.body).to include("Dettaglio sessione").or include("Session details")
|
||||
expect(response.body).to include(session_a.id)
|
||||
end
|
||||
|
||||
it "mostra lo snapshot ingest anche se il nodo è stato decommissionato" do
|
||||
node = StreamNode.create!(
|
||||
slug: "ingest-09",
|
||||
hostname: "ingest-09.mltv-stream.net",
|
||||
role: "cloud",
|
||||
status: "ready",
|
||||
provider: "hetzner",
|
||||
rtmp_base_url: "rtmp://ingest-09.mltv-stream.net:1935",
|
||||
hls_base_url: "https://collaudo.example/hls",
|
||||
api_base_url: "http://10.0.0.9:9997",
|
||||
max_publishers: 4,
|
||||
max_relays: 4
|
||||
)
|
||||
session_a.update!(stream_node: node)
|
||||
node.destroy!
|
||||
session_a.reload
|
||||
|
||||
get admin_sessions_path
|
||||
expect(response).to have_http_status(:ok)
|
||||
expect(response.body).to include("ingest-09")
|
||||
expect(response.body).to include("Hetzner")
|
||||
|
||||
get admin_session_path(session_a)
|
||||
expect(response.body).to include("ingest-09")
|
||||
expect(response.body).to include("nodo rimosso").or include("node removed")
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "rails_helper"
|
||||
|
||||
RSpec.describe "Public replay show youtube-only", type: :request do
|
||||
let!(:club) { Club.create!(name: "Club", sport: "volleyball", primary_color: "#e53935", secondary_color: "#ffffff") }
|
||||
let!(:team) { club.teams.create!(name: "Team", sport: "volleyball") }
|
||||
let!(:user) { User.create!(email: "pub-replay@test.com", name: "Coach", password: "Password123", role: "coach") }
|
||||
let!(:match) { team.matches.create!(opponent_name: "Rival", scheduled_at: 1.day.ago) }
|
||||
let!(:session) do
|
||||
StreamSession.create!(
|
||||
match: match, user: user, platform: "youtube", status: "ended", ended_at: 1.hour.ago,
|
||||
youtube_broadcast_id: "bcast"
|
||||
)
|
||||
end
|
||||
|
||||
it "mostra embed YouTube senza storage_key" do
|
||||
Recording.create!(
|
||||
stream_session: session,
|
||||
team: team,
|
||||
status: "ready",
|
||||
storage_policy: "temporary",
|
||||
storage_key: nil,
|
||||
youtube_video_id: "publicYtVid01",
|
||||
youtube_verified_at: Time.current,
|
||||
local_media_purged_at: Time.current,
|
||||
privacy_status: "public",
|
||||
title: "Derby",
|
||||
expires_at: nil,
|
||||
metadata: { "source_platform" => "youtube" }
|
||||
)
|
||||
|
||||
get "/replay/#{session.id}"
|
||||
expect(response).to have_http_status(:ok)
|
||||
expect(response.body).to include("youtube.com/embed/publicYtVid01")
|
||||
expect(response.body).not_to include("id=\"replay-player\"")
|
||||
end
|
||||
|
||||
it "mostra player MP4 per retained con storage_key" do
|
||||
mltv = StreamSession.create!(
|
||||
match: match, user: user, platform: "matchlivetv", status: "ended", ended_at: 1.hour.ago
|
||||
)
|
||||
Recording.create!(
|
||||
stream_session: mltv,
|
||||
team: team,
|
||||
status: "ready",
|
||||
storage_policy: "retained",
|
||||
storage_key: "teams/#{team.id}/sessions/#{mltv.id}/replay.mp4",
|
||||
privacy_status: "public",
|
||||
title: "Casa",
|
||||
expires_at: 30.days.from_now,
|
||||
metadata: { "source_platform" => "matchlivetv" }
|
||||
)
|
||||
|
||||
get "/replay/#{mltv.id}"
|
||||
expect(response).to have_http_status(:ok)
|
||||
expect(response.body).to include("id=\"replay-player\"")
|
||||
expect(response.body).not_to include("youtube.com/embed/")
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,94 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "rails_helper"
|
||||
|
||||
RSpec.describe "Api::V1 team recordings replay_source", type: :request do
|
||||
let!(:user) { User.create!(email: "rec-api@test.it", name: "U", password: "Password123", role: "coach") }
|
||||
let!(:club) { Club.create!(name: "C", sport: "volleyball", primary_color: "#e53935", secondary_color: "#ffffff") }
|
||||
let!(:owner) { club.club_memberships.create!(user: user, role: "owner") }
|
||||
let!(:team) { club.teams.create!(name: "T", sport: "volleyball") }
|
||||
let!(:match) { team.matches.create!(opponent_name: "Opp", sport: "volleyball", scheduled_at: 1.day.ago) }
|
||||
|
||||
def auth_headers
|
||||
post "/api/v1/auth/login", params: { email: user.email, password: "Password123" }
|
||||
token = response.parsed_body["access_token"]
|
||||
{ "Authorization" => "Bearer #{token}" }
|
||||
end
|
||||
|
||||
before do
|
||||
load Rails.root.join("db/seeds/plans.rb")
|
||||
Billing::AssignPlan.call(club: club, plan_slug: "premium_full")
|
||||
end
|
||||
|
||||
it "youtube-only: replay_source youtube, no playback/download" do
|
||||
session = StreamSession.create!(
|
||||
match: match, user: user, platform: "youtube", status: "ended", ended_at: 1.hour.ago,
|
||||
youtube_broadcast_id: "bcast1"
|
||||
)
|
||||
Recording.create!(
|
||||
stream_session: session,
|
||||
team: team,
|
||||
status: "ready",
|
||||
storage_policy: "temporary",
|
||||
storage_key: nil,
|
||||
youtube_video_id: "ytVideoId123",
|
||||
youtube_verified_at: Time.current,
|
||||
local_media_purged_at: Time.current,
|
||||
privacy_status: "public",
|
||||
expires_at: nil,
|
||||
metadata: { "source_platform" => "youtube" }
|
||||
)
|
||||
|
||||
get "/api/v1/teams/#{team.id}/recordings", headers: auth_headers
|
||||
expect(response).to have_http_status(:ok)
|
||||
item = response.parsed_body.find { |r| r["session_id"] == session.id } ||
|
||||
response.parsed_body.find { |r| r["youtube_video_id"] == "ytVideoId123" }
|
||||
expect(item).to be_present
|
||||
expect(item["replay_source"]).to eq("youtube")
|
||||
expect(item["youtube_watch_url"]).to include("ytVideoId123")
|
||||
expect(item["playback_url"]).to be_nil
|
||||
expect(item["download_enabled"]).to eq(false)
|
||||
end
|
||||
|
||||
it "matchlivetv retained: replay_source matchlivetv with playback" do
|
||||
session = StreamSession.create!(
|
||||
match: match, user: user, platform: "matchlivetv", status: "ended", ended_at: 1.hour.ago
|
||||
)
|
||||
Recording.create!(
|
||||
stream_session: session,
|
||||
team: team,
|
||||
status: "ready",
|
||||
storage_policy: "retained",
|
||||
storage_key: "teams/#{team.id}/sessions/#{session.id}/replay.mp4",
|
||||
privacy_status: "public",
|
||||
expires_at: 30.days.from_now,
|
||||
metadata: { "source_platform" => "matchlivetv" }
|
||||
)
|
||||
|
||||
get "/api/v1/teams/#{team.id}/recordings", headers: auth_headers
|
||||
expect(response).to have_http_status(:ok)
|
||||
item = response.parsed_body.find { |r| r["session_id"] == session.id }
|
||||
expect(item["replay_source"]).to eq("matchlivetv")
|
||||
expect(item["playback_url"]).to be_present
|
||||
expect(item["download_enabled"]).to eq(true)
|
||||
end
|
||||
|
||||
it "download API rejects youtube-only recording" do
|
||||
session = StreamSession.create!(
|
||||
match: match, user: user, platform: "youtube", status: "ended", ended_at: 1.hour.ago
|
||||
)
|
||||
recording = Recording.create!(
|
||||
stream_session: session,
|
||||
team: team,
|
||||
status: "ready",
|
||||
storage_policy: "temporary",
|
||||
storage_key: nil,
|
||||
youtube_video_id: "ytVideoId999",
|
||||
youtube_verified_at: Time.current,
|
||||
privacy_status: "public"
|
||||
)
|
||||
|
||||
get "/api/v1/recordings/#{recording.id}/download", headers: auth_headers
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user