From 8139d84d8896816e9426a8f7a519ff9d79be53bd Mon Sep 17 00:00:00 2001 From: Emiliano Frascaro Date: Thu, 4 Jun 2026 00:03:19 +0200 Subject: [PATCH] Fix orario YouTube scheduledStartTime per dirette immediate. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Normalizza la data partita nel futuro richiesto dall'API: se scheduled_at è passato o assente usa now+5min, con messaggio d'errore più chiaro. Co-authored-by: Cursor --- .../app/services/youtube/broadcast_service.rb | 24 ++++++++++++++- .../youtube/broadcast_service_spec.rb | 30 +++++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 backend/spec/services/youtube/broadcast_service_spec.rb diff --git a/backend/app/services/youtube/broadcast_service.rb b/backend/app/services/youtube/broadcast_service.rb index 8c9688b..1aa7b2a 100644 --- a/backend/app/services/youtube/broadcast_service.rb +++ b/backend/app/services/youtube/broadcast_service.rb @@ -12,10 +12,11 @@ module Youtube return mock_broadcast if @credential.blank? || missing_oauth_config? client = authorized_client + start_time = normalize_scheduled_start_time(scheduled_at) broadcast = Google::Apis::YoutubeV3::LiveBroadcast.new( snippet: Google::Apis::YoutubeV3::LiveBroadcastSnippet.new( title: title, - scheduled_start_time: scheduled_at&.iso8601 + scheduled_start_time: start_time.iso8601 ), status: Google::Apis::YoutubeV3::LiveBroadcastStatus.new( privacy_status: privacy_status, @@ -92,8 +93,29 @@ module Youtube msg = error.message.to_s return "Il canale YouTube non ha la diretta attiva. Apri YouTube Studio con l’account del canale Match Live TV, abilita la live (verifica telefono se richiesto) e riprova." if msg.include?("liveStreamingNotEnabled") return "Credenziali YouTube non valide. Ricollega il canale dalla sezione Admin → YouTube." if msg.match?(/Unauthorized|invalid_grant/i) + if msg.match?(/invalidScheduledStartTime|scheduledStartTimeRequired/i) + return "Orario programmazione YouTube non valido. Riprova: la diretta partirà appena invii il segnale RTMP." + end msg end + + # YouTube richiede scheduledStartTime obbligatorio e nel futuro (non accetta date partita già passate). + def normalize_scheduled_start_time(scheduled_at) + now = Time.current.utc + minimum = now + 5.minutes + maximum = now + 7.days + + candidate = + if scheduled_at.blank? + minimum + else + scheduled_at.utc + end + + candidate = minimum if candidate < minimum + candidate = maximum if candidate > maximum + candidate + end end end diff --git a/backend/spec/services/youtube/broadcast_service_spec.rb b/backend/spec/services/youtube/broadcast_service_spec.rb new file mode 100644 index 0000000..f4cd1c5 --- /dev/null +++ b/backend/spec/services/youtube/broadcast_service_spec.rb @@ -0,0 +1,30 @@ +require "rails_helper" + +RSpec.describe Youtube::BroadcastService do + describe "#normalize_scheduled_start_time" do + subject(:service) { described_class.allocate } + + it "usa tra 5 minuti se scheduled_at è assente" do + travel_to Time.zone.parse("2026-06-03 20:00:00 UTC") do + t = service.send(:normalize_scheduled_start_time, nil) + expect(t).to eq(Time.utc(2026, 6, 3, 20, 5, 0)) + end + end + + it "sposta nel futuro se scheduled_at è nel passato" do + travel_to Time.zone.parse("2026-06-03 20:00:00 UTC") do + past = Time.zone.parse("2026-06-03 10:00:00") + t = service.send(:normalize_scheduled_start_time, past) + expect(t).to eq(Time.utc(2026, 6, 3, 20, 5, 0)) + end + end + + it "mantiene scheduled_at se è nel futuro entro 7 giorni" do + travel_to Time.zone.parse("2026-06-03 20:00:00 UTC") do + future = Time.zone.parse("2026-06-05 18:00:00") + t = service.send(:normalize_scheduled_start_time, future) + expect(t).to eq(future.utc) + end + end + end +end