89 lines
2.5 KiB
Ruby
89 lines
2.5 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
module Youtube
|
|
# Stato VOD dopo una live (broadcast_id ≈ video_id su YouTube).
|
|
class VodStatus
|
|
class Error < StandardError; end
|
|
|
|
Result = Struct.new(
|
|
:ready,
|
|
:video_id,
|
|
:title,
|
|
:duration_secs,
|
|
:thumbnail_url,
|
|
:privacy_status,
|
|
:upload_status,
|
|
:embeddable,
|
|
keyword_init: true
|
|
)
|
|
|
|
def initialize(team, channel: "team")
|
|
@team = team
|
|
@channel = channel
|
|
end
|
|
|
|
def fetch(video_id)
|
|
raise Error, "video_id mancante" if video_id.blank?
|
|
|
|
if mock_or_unconfigured?(video_id)
|
|
return Result.new(
|
|
ready: true,
|
|
video_id: video_id,
|
|
title: nil,
|
|
duration_secs: nil,
|
|
thumbnail_url: nil,
|
|
privacy_status: "unlisted",
|
|
upload_status: "processed",
|
|
embeddable: true
|
|
)
|
|
end
|
|
|
|
client = authorized_client
|
|
item = client.list_videos("snippet,contentDetails,status", id: video_id).items&.first
|
|
return Result.new(ready: false, video_id: video_id) if item.blank?
|
|
|
|
upload_status = item.status&.upload_status.to_s
|
|
ready = upload_status.in?(%w[processed uploaded]) ||
|
|
(item.snippet.present? && upload_status != "deleted" && upload_status != "rejected" && upload_status != "failed")
|
|
|
|
Result.new(
|
|
ready: ready,
|
|
video_id: item.id,
|
|
title: item.snippet&.title,
|
|
duration_secs: parse_duration(item.content_details&.duration),
|
|
thumbnail_url: item.snippet&.thumbnails&.high&.url || item.snippet&.thumbnails&.default&.url,
|
|
privacy_status: item.status&.privacy_status,
|
|
upload_status: upload_status,
|
|
embeddable: item.status&.embeddable != false
|
|
)
|
|
rescue Google::Apis::Error => e
|
|
raise Error, e.message
|
|
end
|
|
|
|
private
|
|
|
|
def mock_or_unconfigured?(video_id)
|
|
video_id.to_s.start_with?("mock_") ||
|
|
ENV["YOUTUBE_CLIENT_ID"].blank? ||
|
|
CredentialResolver.new(@team, channel: @channel).resolve.blank?
|
|
end
|
|
|
|
def authorized_client
|
|
credential = CredentialResolver.new(@team, channel: @channel).resolve
|
|
raise Error, "Credenziali YouTube non disponibili" if credential.blank?
|
|
|
|
OauthRefresh.new(credential).apply!(Google::Apis::YoutubeV3::YouTubeService.new)
|
|
end
|
|
|
|
def parse_duration(iso)
|
|
return nil if iso.blank?
|
|
|
|
# PT1H2M3S
|
|
match = iso.match(/\APT(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?\z/)
|
|
return nil unless match
|
|
|
|
match[1].to_i * 3600 + match[2].to_i * 60 + match[3].to_i
|
|
end
|
|
end
|
|
end
|