Files
turbovault-app/app/jobs/igdb_sync_job.rb
2026-03-29 02:37:49 -04:00

139 lines
3.9 KiB
Ruby

class IgdbSyncJob < ApplicationJob
queue_as :default
# Ensure only one instance runs at a time
def self.running?
Rails.cache.exist?("igdb_sync_job:running")
end
def self.mark_running!
Rails.cache.write("igdb_sync_job:running", true, expires_in: 2.hours)
end
def self.mark_finished!
Rails.cache.delete("igdb_sync_job:running")
end
def perform
# Prevent multiple instances
if self.class.running?
Rails.logger.info("IgdbSyncJob already running, skipping...")
return
end
self.class.mark_running!
begin
sync_users_with_igdb
ensure
self.class.mark_finished!
end
end
private
def sync_users_with_igdb
users = User.where(igdb_sync_enabled: true)
Rails.logger.info("Starting IGDB sync for #{users.count} users")
users.find_each do |user|
sync_user_games(user)
rescue => e
Rails.logger.error("Error syncing user #{user.id}: #{e.message}")
next
end
Rails.logger.info("IGDB sync completed")
end
def sync_user_games(user)
# Get games that need IGDB matching
games = user.games
.igdb_unmatched
.where(igdb_match_status: [ nil, "failed" ])
.includes(:platform)
return if games.empty?
Rails.logger.info("Syncing #{games.count} games for user #{user.id}")
igdb_service = IgdbService.new
games_synced = 0
games.find_each do |game|
process_game_matching(game, igdb_service)
games_synced += 1
# Rate limiting: Additional sleep every 10 games
sleep(1) if games_synced % 10 == 0
rescue => e
Rails.logger.error("Error processing game #{game.id}: #{e.message}")
game.update(igdb_match_status: "failed")
next
end
user.update(igdb_last_synced_at: Time.current)
end
def process_game_matching(game, igdb_service)
Rails.logger.info("Searching IGDB for: #{game.title} (#{game.platform.name})")
# Try searching WITH platform first
results = igdb_service.search_game(game.title, game.platform, 3)
# If no results, try WITHOUT platform (broader search)
if results.empty?
Rails.logger.info("No results with platform, trying without platform filter...")
results = igdb_service.search_game(game.title, nil, 3)
end
if results.empty?
Rails.logger.info("No IGDB matches found for game #{game.id}")
game.update(igdb_match_status: "no_results")
return
end
Rails.logger.info("Found #{results.count} potential matches for game #{game.id}")
# Create match suggestions for user review
results.each do |result|
create_match_suggestion(game, result)
end
# Update game status
if results.first[:confidence_score] >= 95.0
# Very high confidence - could auto-approve, but we'll let user review
game.update(igdb_match_status: "high_confidence")
elsif results.first[:confidence_score] >= 70.0
game.update(igdb_match_status: "medium_confidence")
else
game.update(igdb_match_status: "low_confidence")
end
end
def create_match_suggestion(game, result)
# Skip if suggestion already exists
existing = IgdbMatchSuggestion.find_by(game: game, igdb_id: result[:igdb_id])
return if existing
IgdbMatchSuggestion.create!(
game: game,
igdb_id: result[:igdb_id],
igdb_name: result[:name],
igdb_slug: result[:slug],
igdb_cover_url: result[:cover_url],
igdb_summary: result[:summary],
igdb_release_date: result[:release_date],
igdb_platform_name: result[:platform_name],
igdb_genres: result[:genres] || [],
confidence_score: result[:confidence_score],
status: "pending"
)
Rails.logger.info("Created match suggestion: #{result[:name]} (confidence: #{result[:confidence_score]}%)")
rescue ActiveRecord::RecordInvalid => e
Rails.logger.warn("Failed to create match suggestion: #{e.message}")
end
end