Class: NexusMods
- Inherits:
-
Object
- Object
- NexusMods
- Defined in:
- lib/nexus_mods.rb,
lib/nexus_mods/api/mod.rb,
lib/nexus_mods/version.rb,
lib/nexus_mods/api/game.rb,
lib/nexus_mods/api/user.rb,
lib/nexus_mods/api_client.rb,
lib/nexus_mods/api/category.rb,
lib/nexus_mods/api/mod_file.rb,
lib/nexus_mods/api/resource.rb,
lib/nexus_mods/cacheable_api.rb,
lib/nexus_mods/api/api_limits.rb,
lib/nexus_mods/api/mod_updates.rb,
lib/nexus_mods/cacheable_with_expiry.rb,
lib/nexus_mods/core_extensions/cacheable/method_generator.rb
Overview
Ruby API to access NexusMods REST API
Defined Under Namespace
Modules: Api, CacheableApi, CacheableWithExpiry, CoreExtensions Classes: ApiClient, ApiError, InvalidApiKeyError, LimitsExceededError
Constant Summary collapse
- VERSION =
'2.5.0'
Instance Attribute Summary collapse
-
#game_domain_name ⇒ Object
The default game domain name to be queried String.
-
#mod_id ⇒ Object
The default mod id to be queried Integer.
Instance Method Summary collapse
-
#api_limits ⇒ Object
Get limits of API calls.
-
#games(clear_cache: false) ⇒ Object
Get the list of games.
-
#games_cache_timestamp ⇒ Object
Get the cached timestamp of the list of games.
-
#initialize(api_key: nil, game_domain_name: 'skyrimspecialedition', mod_id: 1, file_id: 1, api_cache_expiry: {}, api_cache_file: "#{Dir.tmpdir}/nexus_mods_api_cache.json", logger: Logger.new($stdout), log_level: :info) ⇒ NexusMods
constructor
Constructor.
-
#mod(game_domain_name: @game_domain_name, mod_id: @mod_id, clear_cache: false, check_updates: false) ⇒ Object
Get information about a mod.
-
#mod_cache_timestamp(game_domain_name: @game_domain_name, mod_id: @mod_id) ⇒ Object
Get the cached timestamp of a mod information.
-
#mod_cache_up_to_date?(game_domain_name: @game_domain_name, mod_id: @mod_id) ⇒ Boolean
Does a given mod id have fresh information in our cache? This may fire queries to the updated mods API to get info from NexusMods about the latest updated mods.
-
#mod_files(game_domain_name: @game_domain_name, mod_id: @mod_id, clear_cache: false, check_updates: false) ⇒ Object
Get files belonging to a mod.
-
#mod_files_cache_timestamp(game_domain_name: @game_domain_name, mod_id: @mod_id) ⇒ Object
Get the cached timestamp of a mod files information.
-
#mod_files_cache_up_to_date?(game_domain_name: @game_domain_name, mod_id: @mod_id) ⇒ Boolean
Does a given mod id have fresh files information in our cache? This may fire queries to the updated mods API to get info from NexusMods about the latest updated mods.
-
#set_games_cache_timestamp(cache_timestamp:) ⇒ Object
Set the cached timestamp of the list of games.
-
#set_mod_cache_timestamp(cache_timestamp:, game_domain_name: @game_domain_name, mod_id: @mod_id) ⇒ Object
Set the cached timestamp of a mod information.
-
#set_mod_files_cache_timestamp(cache_timestamp:, game_domain_name: @game_domain_name, mod_id: @mod_id) ⇒ Object
Set the cached timestamp of a mod files information.
-
#set_updated_mods_cache_timestamp(cache_timestamp:, game_domain_name: @game_domain_name, since: :one_day) ⇒ Object
Set the cached timestamp of updated mod ids.
-
#updated_mods(game_domain_name: @game_domain_name, since: :one_day, clear_cache: false) ⇒ Object
Get a list of updated mod ids since a given time.
-
#updated_mods_cache_timestamp(game_domain_name: @game_domain_name, since: :one_day) ⇒ Object
Get the cached timestamp of updated mod ids.
Constructor Details
#initialize(api_key: nil, game_domain_name: 'skyrimspecialedition', mod_id: 1, file_id: 1, api_cache_expiry: {}, api_cache_file: "#{Dir.tmpdir}/nexus_mods_api_cache.json", logger: Logger.new($stdout), log_level: :info) ⇒ NexusMods
Constructor
- Parameters
-
api_key (String or nil): The API key to be used, or nil for another authentication [default: nil]
-
game_domain_name (String): Game domain name to query by default [default: ‘skyrimspecialedition’]
-
mod_id (Integer): Mod to query by default [default: 1]
-
file_id (Integer): File to query by default [default: 1]
-
api_cache_expiry (Hash<Symbol,Integer>): Expiry times in seconds, per expiry key. Possible keys are:
-
games: Expiry associated to queries on games [default: 1 day]
-
mod: Expiry associated to queries on mod [default: 1 day]
-
mod_files: Expiry associated to queries on mod files [default: 1 day]
-
-
api_cache_file (String): File used to store the NexusMods API cache, or nil for no cache [default: “#Dir.tmpdir/nexus_mods_api_cache.json”]
-
logger (Logger): The logger to be used for log messages [default: Logger.new(STDOUT)]
-
log_level (Symbol): The logger level to be set [default: :info]
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
# File 'lib/nexus_mods.rb', line 50 def initialize( api_key: nil, game_domain_name: 'skyrimspecialedition', mod_id: 1, file_id: 1, api_cache_expiry: {}, api_cache_file: "#{Dir.tmpdir}/nexus_mods_api_cache.json", logger: Logger.new($stdout), log_level: :info ) @game_domain_name = game_domain_name @mod_id = mod_id @file_id = file_id @logger = logger @logger.level = log_level @premium = false @api_client = ApiClient.new( api_key:, api_cache_expiry:, api_cache_file:, logger: ) # Check that the key is correct and know if the user is premium begin @premium = @api_client.api('users/validate')['is_premium?'] rescue LimitsExceededError raise rescue ApiError raise InvalidApiKeyError, 'Invalid API key' end end |
Instance Attribute Details
#game_domain_name ⇒ Object
The default game domain name to be queried
String
30 31 32 |
# File 'lib/nexus_mods.rb', line 30 def game_domain_name @game_domain_name end |
#mod_id ⇒ Object
The default mod id to be queried
Integer
34 35 36 |
# File 'lib/nexus_mods.rb', line 34 def mod_id @mod_id end |
Instance Method Details
#api_limits ⇒ Object
Get limits of API calls. This call does not count in the limits.
- Result
-
ApiLimits: API calls limits
88 89 90 91 92 93 94 95 96 97 98 99 |
# File 'lib/nexus_mods.rb', line 88 def api_limits api_limits_headers = @api_client.http('users/validate').headers Api::ApiLimits.new( nexus_mods: self, daily_limit: Integer(api_limits_headers['x-rl-daily-limit']), daily_remaining: Integer(api_limits_headers['x-rl-daily-remaining']), daily_reset: Time.parse(api_limits_headers['x-rl-daily-reset']).utc, hourly_limit: Integer(api_limits_headers['x-rl-hourly-limit']), hourly_remaining: Integer(api_limits_headers['x-rl-hourly-remaining']), hourly_reset: Time.parse(api_limits_headers['x-rl-hourly-reset']).utc ) end |
#games(clear_cache: false) ⇒ Object
Get the list of games
- Parameters
-
clear_cache (Boolean): Should we clear the API cache for this resource? [default: false]
- Result
-
Array<Game>: List of games
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 |
# File 'lib/nexus_mods.rb', line 107 def games(clear_cache: false) @api_client.api('games', clear_cache:).map do |game_json| # First create categories tree # Hash<Integer, [Category, Integer]>: Category and its parent category id, per category id categories = game_json['categories'].to_h do |category_json| category_id = category_json['category_id'] [ category_id, [ Api::Category.new( nexus_mods: self, id: category_id, name: category_json['name'] ), category_json['parent_category'] ] ] end categories.each_value do |(category, parent_category_id)| # Ignore missing parent categories: this situation happens. category.parent_category = categories[parent_category_id]&.first if parent_category_id end Api::Game.new( nexus_mods: self, id: game_json['id'], name: game_json['name'], forum_url: game_json['forum_url'], nexusmods_url: game_json['nexusmods_url'], genre: game_json['genre'], domain_name: game_json['domain_name'], approved_date: Time.at(game_json['approved_date']).utc, files_count: game_json['file_count'], files_views: game_json['file_views'], files_endorsements: game_json['file_endorsements'], downloads_count: game_json['downloads'], authors_count: game_json['authors'], mods_count: game_json['mods'], categories: categories.values.map { |(category, _parent_category_id)| category } ) end end |
#games_cache_timestamp ⇒ Object
Get the cached timestamp of the list of games
- Result
-
Time or nil: Freshness time of the data in the API cache, or nil if not present in the cache
153 154 155 |
# File 'lib/nexus_mods.rb', line 153 def @api_client.('games') end |
#mod(game_domain_name: @game_domain_name, mod_id: @mod_id, clear_cache: false, check_updates: false) ⇒ Object
Get information about a mod
- Parameters
-
game_domain_name (String): Game domain name to query by default [default: @game_domain_name]
-
mod_id (Integer): The mod ID [default: @mod_id]
-
clear_cache (Boolean): Should we clear the API cache for this resource? [default: false]
-
check_updates (Boolean): Should we check updates? If yes then an extra call to updated_mods may be done to check for updates before retrieving the mod information. In case the mod was previously retrieved and may be in an old cache, then using this will optimize the calls to NexusMods API to the minimum.
- Result
-
Mod: Mod information
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 |
# File 'lib/nexus_mods.rb', line 177 def mod(game_domain_name: @game_domain_name, mod_id: @mod_id, clear_cache: false, check_updates: false) mod_cache_up_to_date?(game_domain_name:, mod_id:) if check_updates mod_json = @api_client.api("games/#{game_domain_name}/mods/#{mod_id}", clear_cache:) Api::Mod.new( nexus_mods: self, uid: mod_json['uid'], mod_id: mod_json['mod_id'], game_id: mod_json['game_id'], allow_rating: mod_json['allow_rating'], domain_name: mod_json['domain_name'], category_id: mod_json['category_id'], version: mod_json['version'], created_time: Time.parse(mod_json['created_time']), updated_time: Time.parse(mod_json['updated_time']), author: mod_json['author'], contains_adult_content: mod_json['contains_adult_content'], status: mod_json['status'], available: mod_json['available'], uploader: Api::User.new( nexus_mods: self, member_id: mod_json['user']['member_id'], member_group_id: mod_json['user']['member_group_id'], name: mod_json['user']['name'], profile_url: mod_json['uploaded_users_profile_url'] ), name: mod_json['name'], summary: mod_json['summary'], description: mod_json['description'], picture_url: mod_json['picture_url'], downloads_count: mod_json['mod_downloads'], unique_downloads_count: mod_json['mod_unique_downloads'], endorsements_count: mod_json['endorsement_count'] ) end |
#mod_cache_timestamp(game_domain_name: @game_domain_name, mod_id: @mod_id) ⇒ Object
Get the cached timestamp of a mod information
- Parameters
-
game_domain_name (String): Game domain name to query by default [default: @game_domain_name]
-
mod_id (Integer): The mod ID [default: @mod_id]
- Result
-
Time or nil: Freshness time of the data in the API cache, or nil if not present in the cache
219 220 221 |
# File 'lib/nexus_mods.rb', line 219 def (game_domain_name: @game_domain_name, mod_id: @mod_id) @api_client.("games/#{game_domain_name}/mods/#{mod_id}") end |
#mod_cache_up_to_date?(game_domain_name: @game_domain_name, mod_id: @mod_id) ⇒ Boolean
Does a given mod id have fresh information in our cache? This may fire queries to the updated mods API to get info from NexusMods about the latest updated mods. If we know the mod is up-to-date, then its mod information cache timestamp will be set to the time when we checked for updates if it was greater than the cache date.
Here is the algorithm: If it is not in the cache, then it is not up-to-date. Otherwise, the API allows us to know if it has been updated up to 1 month in the past. Therefore if the current cache timestamp is older than 1 month, assume that it has to be updated. Otherwise query the API to know the latest updated mods since 1 month:
-
If the mod ID is not there, then it is up-to-date.
-
If the mod ID is there, then check if our cache timestamp is older than the last update timestamp from NexusMods.
- Parameters
-
game_domain_name (String): Game domain name to query by default [default: @game_domain_name]
-
mod_id (Integer): The mod ID [default: @mod_id]
- Result
-
Boolean: Is the mod cache up-to-date?
365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 |
# File 'lib/nexus_mods.rb', line 365 def mod_cache_up_to_date?(game_domain_name: @game_domain_name, mod_id: @mod_id) = (game_domain_name:, mod_id:) mod_up_to_date = if .nil? || < Time.now - (30 * 24 * 60 * 60) # It's not in the cache # or it's older than 1 month false else found_mod_updates = updated_mods(game_domain_name:, since: :one_month).find { |mod_updates| mod_updates.mod_id == mod_id } # true if it has not been updated on NexusMods since 1 month # or our cache timestamp is more recent found_mod_updates.nil? || found_mod_updates.latest_mod_activity < end if mod_up_to_date update_time = (game_domain_name:, since: :one_month) (cache_timestamp: update_time, game_domain_name:, mod_id:) if update_time > end mod_up_to_date end |
#mod_files(game_domain_name: @game_domain_name, mod_id: @mod_id, clear_cache: false, check_updates: false) ⇒ Object
Get files belonging to a mod
- Parameters
-
game_domain_name (String): Game domain name to query by default [default: @game_domain_name]
-
mod_id (Integer): The mod ID [default: @mod_id]
-
clear_cache (Boolean): Should we clear the API cache for this resource? [default: false]
-
check_updates (Boolean): Should we check updates? If yes then an extra call to updated_mods may be done to check for updates before retrieving the mod information. In case the mod files were previously retrieved and may be in an old cache, then using this will optimize the calls to NexusMods API to the minimum.
- Result
-
Array<ModFile>: List of mod’s files
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 |
# File 'lib/nexus_mods.rb', line 245 def mod_files(game_domain_name: @game_domain_name, mod_id: @mod_id, clear_cache: false, check_updates: false) mod_files_cache_up_to_date?(game_domain_name:, mod_id:) if check_updates @api_client.api("games/#{game_domain_name}/mods/#{mod_id}/files", clear_cache:)['files'].map do |file_json| Api::ModFile.new( nexus_mods: self, game_domain_name:, mod_id:, ids: file_json['id'], uid: file_json['uid'], id: file_json['file_id'], name: file_json['name'], version: file_json['version'], category_id: file_json['category_id'], category_name: file_json['category_name'], is_primary: file_json['is_primary'], size: file_json['size_in_bytes'], file_name: file_json['file_name'], uploaded_time: Time.parse(file_json['uploaded_time']), mod_version: file_json['mod_version'], external_virus_scan_url: file_json['external_virus_scan_url'], description: file_json['description'], changelog_html: file_json['changelog_html'], content_preview_url: file_json['content_preview_link'] ) end end |
#mod_files_cache_timestamp(game_domain_name: @game_domain_name, mod_id: @mod_id) ⇒ Object
Get the cached timestamp of a mod files information
- Parameters
-
game_domain_name (String): Game domain name to query by default [default: @game_domain_name]
-
mod_id (Integer): The mod ID [default: @mod_id]
- Result
-
Time or nil: Freshness time of the data in the API cache, or nil if not present in the cache
279 280 281 |
# File 'lib/nexus_mods.rb', line 279 def (game_domain_name: @game_domain_name, mod_id: @mod_id) @api_client.("games/#{game_domain_name}/mods/#{mod_id}/files") end |
#mod_files_cache_up_to_date?(game_domain_name: @game_domain_name, mod_id: @mod_id) ⇒ Boolean
Does a given mod id have fresh files information in our cache? This may fire queries to the updated mods API to get info from NexusMods about the latest updated mods. If we know the mod is up-to-date, then its mod information cache timestamp will be set to the time when we checked for updates if it was greater than the cache date.
Here is the algorithm: If it is not in the cache, then it is not up-to-date. Otherwise, the API allows us to know if it has been updated up to 1 month in the past. Therefore if the current cache timestamp is older than 1 month, assume that it has to be updated. Otherwise query the API to know the latest updated mods since 1 month:
-
If the mod ID is not there, then it is up-to-date.
-
If the mod ID is there, then check if our cache timestamp is older than the last update timestamp from NexusMods.
- Parameters
-
game_domain_name (String): Game domain name to query by default [default: @game_domain_name]
-
mod_id (Integer): The mod ID [default: @mod_id]
- Result
-
Boolean: Is the mod cache up-to-date?
402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 |
# File 'lib/nexus_mods.rb', line 402 def mod_files_cache_up_to_date?(game_domain_name: @game_domain_name, mod_id: @mod_id) = (game_domain_name:, mod_id:) mod_up_to_date = if .nil? || < Time.now - (30 * 24 * 60 * 60) # It's not in the cache # or it's older than 1 month false else found_mod_updates = updated_mods(game_domain_name:, since: :one_month).find { |mod_updates| mod_updates.mod_id == mod_id } # true if it has not been updated on NexusMods since 1 month # or our cache timestamp is more recent found_mod_updates.nil? || found_mod_updates.latest_file_update < end if mod_up_to_date update_time = (game_domain_name:, since: :one_month) (cache_timestamp: update_time, game_domain_name:, mod_id:) if update_time > end mod_up_to_date end |
#set_games_cache_timestamp(cache_timestamp:) ⇒ Object
Set the cached timestamp of the list of games. This should be used only to update the cache timestamp of a resource we know is still up-to-date without fetching the resource for real again.
- Parameters
-
cache_timestamp (Time): The cache timestamp to set for this resource
162 163 164 |
# File 'lib/nexus_mods.rb', line 162 def (cache_timestamp:) @api_client.('games', cache_timestamp:) end |
#set_mod_cache_timestamp(cache_timestamp:, game_domain_name: @game_domain_name, mod_id: @mod_id) ⇒ Object
Set the cached timestamp of a mod information. This should be used only to update the cache timestamp of a resource we know is still up-to-date without fetching the resource for real again.
- Parameters
-
game_domain_name (String): Game domain name to query by default [default: @game_domain_name]
-
mod_id (Integer): The mod ID [default: @mod_id]
-
cache_timestamp (Time): The cache timestamp to set for this resource
230 231 232 |
# File 'lib/nexus_mods.rb', line 230 def (cache_timestamp:, game_domain_name: @game_domain_name, mod_id: @mod_id) @api_client.("games/#{game_domain_name}/mods/#{mod_id}", cache_timestamp:) end |
#set_mod_files_cache_timestamp(cache_timestamp:, game_domain_name: @game_domain_name, mod_id: @mod_id) ⇒ Object
Set the cached timestamp of a mod files information. This should be used only to update the cache timestamp of a resource we know is still up-to-date without fetching the resource for real again.
- Parameters
-
game_domain_name (String): Game domain name to query by default [default: @game_domain_name]
-
mod_id (Integer): The mod ID [default: @mod_id]
-
cache_timestamp (Time): The cache timestamp to set for this resource
290 291 292 |
# File 'lib/nexus_mods.rb', line 290 def (cache_timestamp:, game_domain_name: @game_domain_name, mod_id: @mod_id) @api_client.("games/#{game_domain_name}/mods/#{mod_id}/files", cache_timestamp:) end |
#set_updated_mods_cache_timestamp(cache_timestamp:, game_domain_name: @game_domain_name, since: :one_day) ⇒ Object
Set the cached timestamp of updated mod ids. This should be used only to update the cache timestamp of a resource we know is still up-to-date without fetching the resource for real again.
- Parameters
-
game_domain_name (String): Game domain name to query by default [default: @game_domain_name]
-
since (Symbol): The time from which we look for updated mods [default: :one_day] Possible values are:
-
one_day: Since 1 day
-
one_week: Since 1 week
-
one_month: Since 1 month
-
-
cache_timestamp (Time): The cache timestamp to set for this resource
344 345 346 |
# File 'lib/nexus_mods.rb', line 344 def (cache_timestamp:, game_domain_name: @game_domain_name, since: :one_day) @api_client.("games/#{game_domain_name}/mods/updated", parameters: period_to_url_params(since), cache_timestamp:) end |
#updated_mods(game_domain_name: @game_domain_name, since: :one_day, clear_cache: false) ⇒ Object
Get a list of updated mod ids since a given time
- Parameters
-
game_domain_name (String): Game domain name to query by default [default: @game_domain_name]
-
since (Symbol): The time from which we look for updated mods [default: :one_day] Possible values are:
-
one_day: Since 1 day
-
one_week: Since 1 week
-
one_month: Since 1 month
-
-
clear_cache (Boolean): Should we clear the API cache for this resource? [default: false]
- Result
-
Array<ModUpdates>: Mod’s updates information
306 307 308 309 310 311 312 313 314 315 316 |
# File 'lib/nexus_mods.rb', line 306 def updated_mods(game_domain_name: @game_domain_name, since: :one_day, clear_cache: false) @api_client.api("games/#{game_domain_name}/mods/updated", parameters: period_to_url_params(since), clear_cache:).map do |updated_mod_json| Api::ModUpdates.new( nexus_mods: self, game_domain_name:, mod_id: updated_mod_json['mod_id'], latest_file_update: Time.at(updated_mod_json['latest_file_update']).utc, latest_mod_activity: Time.at(updated_mod_json['latest_mod_activity']).utc ) end end |
#updated_mods_cache_timestamp(game_domain_name: @game_domain_name, since: :one_day) ⇒ Object
Get the cached timestamp of updated mod ids
- Parameters
-
game_domain_name (String): Game domain name to query by default [default: @game_domain_name]
-
since (Symbol): The time from which we look for updated mods [default: :one_day] Possible values are:
-
one_day: Since 1 day
-
one_week: Since 1 week
-
one_month: Since 1 month
-
- Result
-
Time or nil: Freshness time of the data in the API cache, or nil if not present in the cache
329 330 331 |
# File 'lib/nexus_mods.rb', line 329 def (game_domain_name: @game_domain_name, since: :one_day) @api_client.("games/#{game_domain_name}/mods/updated", parameters: period_to_url_params(since)) end |