Class: YouTube::SyncService
- Inherits:
-
Object
- Object
- YouTube::SyncService
- Defined in:
- app/services/youtube/sync_service.rb
Overview
Synchronizes YouTube video metadata with local Video records.
Two sync directions:
- Pull: fetch video details from YouTube for videos with youtube_id set
- Full: list all channel videos and match/flag unlinked ones
Instance Attribute Summary collapse
-
#client ⇒ Object
readonly
Returns the value of attribute client.
-
#logger ⇒ Object
readonly
Returns the value of attribute logger.
Instance Method Summary collapse
-
#find_unlinked_channel_videos ⇒ Array<Hash>
List all videos on the connected YouTube channel and return any that don't have a matching local Video record.
-
#initialize(account: nil, client: nil) ⇒ SyncService
constructor
A new instance of SyncService.
-
#sync_existing_videos ⇒ Hash
Sync metadata for all Video records that have a youtube_id.
-
#sync_video(video_id) ⇒ Video?
Sync a single video by its local ID.
Constructor Details
#initialize(account: nil, client: nil) ⇒ SyncService
Returns a new instance of SyncService.
13 14 15 16 |
# File 'app/services/youtube/sync_service.rb', line 13 def initialize(account: nil, client: nil) @client = client || YouTube::ApiClient.new(account: account) @logger = Rails.logger end |
Instance Attribute Details
#client ⇒ Object (readonly)
Returns the value of attribute client.
11 12 13 |
# File 'app/services/youtube/sync_service.rb', line 11 def client @client end |
#logger ⇒ Object (readonly)
Returns the value of attribute logger.
11 12 13 |
# File 'app/services/youtube/sync_service.rb', line 11 def logger @logger end |
Instance Method Details
#find_unlinked_channel_videos ⇒ Array<Hash>
List all videos on the connected YouTube channel and return
any that don't have a matching local Video record.
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
# File 'app/services/youtube/sync_service.rb', line 70 def find_unlinked_channel_videos channel = @client.my_channel return [] unless channel channel_id = channel.id existing_youtube_ids = Video.where.not(youtube_id: [nil, '']).pluck(:youtube_id).to_set unlinked = [] page_token = nil loop do response = @client.list_channel_videos(channel_id: channel_id, page_token: page_token) break if response.items.blank? response.items.each do |item| yt_id = item.id.video_id next if existing_youtube_ids.include?(yt_id) unlinked << { youtube_id: yt_id, title: item.snippet.title, published_at: item.snippet.published_at } end page_token = response.next_page_token break if page_token.blank? end unlinked end |
#sync_existing_videos ⇒ Hash
Sync metadata for all Video records that have a youtube_id.
Fetches data from YouTube in batches of 50 (API max).
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
# File 'app/services/youtube/sync_service.rb', line 21 def sync_existing_videos videos = Video.where.not(youtube_id: [nil, '']) return { synced: 0, errors: 0, skipped: 0 } if videos.none? stats = { synced: 0, errors: 0, skipped: 0 } videos.pluck(:id, :youtube_id).each_slice(50) do |batch| youtube_ids = batch.map(&:last) video_id_map = batch.to_h { |id, yt_id| [yt_id, id] } begin yt_videos = @client.get_videos(youtube_ids, parts: 'snippet,contentDetails,status') yt_videos.each do |yt_video| local_id = video_id_map[yt_video.id] next unless local_id (local_id, yt_video) stats[:synced] += 1 rescue StandardError => e logger.error("[YouTube::SyncService] Error syncing video #{local_id}: #{e.}") stats[:errors] += 1 end rescue YouTube::ApiClient::ApiError => e logger.error("[YouTube::SyncService] Batch API error: #{e.}") stats[:errors] += batch.size end end stats end |
#sync_video(video_id) ⇒ Video?
Sync a single video by its local ID.
56 57 58 59 60 61 62 63 64 65 |
# File 'app/services/youtube/sync_service.rb', line 56 def sync_video(video_id) video = Video.find(video_id) return nil if video.youtube_id.blank? yt_video = @client.get_video(video.youtube_id) return nil unless yt_video (video.id, yt_video) video.reload end |