module VideoSources module Youtube class Client API_BASE = 'https://www.googleapis.com/youtube/v3' def initialize api_key: ENV.fetch('YOUTUBE_API_KEY') @api_key = api_key end def videos video_ids return [] if video_ids.empty? response = connection.get('videos', part: 'snippet,statistics', id: video_ids.join(','), key: @api_key) JSON.parse(response.body).fetch('items', []).map do |item| build_video(item) end end def comments video_id comments = [] page_token = nil loop do response = connection.get('commentThreads', { part: 'snippet', videoId: video_id, maxResults: 100, textFormat: 'plainText', pageToken: page_token, key: @api_key }.compact) body = JSON.parse(response.body) comments.concat(body.fetch('items', []).map { |item| build_comment(item) }) page_token = body['nextPageToken'] break if page_token.blank? end comments rescue Faraday::ForbiddenError [] end private def connection @connection ||= Faraday.new(url: API_BASE) do |faraday| faraday.response :raise_error end end def build_video item snippet = item.fetch('snippet') statistics = item.fetch('statistics', { }) { provider: 'youtube', code: item.fetch('id'), user_code: snippet['channelId'], title: snippet['title'].to_s, description: snippet['description'].to_s, tag_names: snippet.fetch('tags', []), views_count: statistics.fetch('viewCount', 0).to_i, uploaded_at: Time.zone.parse(snippet.fetch('publishedAt')) } end def build_comment item snippet = item .fetch('snippet') .fetch('topLevelComment') .fetch('snippet') { provider_comment_id: item.fetch('id'), user_code: snippet['authorChannelId']&.fetch('value', nil), content: snippet['textDisplay'].to_s, posted_at: Time.zone.parse(snippet.fetch('publishedAt')), reaction_count: snippet.fetch('likeCount', 0).to_i, comment_no: nil, vpos_ms: nil } end end end end