Class: NexusMods

Inherits:
Object
  • Object
show all
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/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.2.0'

Instance Attribute Summary collapse

Instance Method Summary collapse

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_nameObject

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_idObject

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_limitsObject

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
# File 'lib/nexus_mods.rb', line 88

def api_limits
  api_limits_headers = @api_client.http('users/validate').headers
  Api::ApiLimits.new(
    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



106
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
# File 'lib/nexus_mods.rb', line 106

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(
            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(
      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_timestampObject

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



150
151
152
# File 'lib/nexus_mods.rb', line 150

def games_cache_timestamp
  @api_client.api_cache_timestamp('games')
end

#mod(game_domain_name: @game_domain_name, mod_id: @mod_id, clear_cache: 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]

Result
  • Mod: Mod information



162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
# File 'lib/nexus_mods.rb', line 162

def mod(game_domain_name: @game_domain_name, mod_id: @mod_id, clear_cache: false)
  mod_json = @api_client.api("games/#{game_domain_name}/mods/#{mod_id}", clear_cache:)
  Api::Mod.new(
    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(
      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



201
202
203
# File 'lib/nexus_mods.rb', line 201

def mod_cache_timestamp(game_domain_name: @game_domain_name, mod_id: @mod_id)
  @api_client.api_cache_timestamp("games/#{game_domain_name}/mods/#{mod_id}")
end

#mod_files(game_domain_name: @game_domain_name, mod_id: @mod_id, clear_cache: 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]

Result
  • Array<ModFile>: List of mod’s files



213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
# File 'lib/nexus_mods.rb', line 213

def mod_files(game_domain_name: @game_domain_name, mod_id: @mod_id, clear_cache: false)
  @api_client.api("games/#{game_domain_name}/mods/#{mod_id}/files", clear_cache:)['files'].map do |file_json|
    Api::ModFile.new(
      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



243
244
245
# File 'lib/nexus_mods.rb', line 243

def mod_files_cache_timestamp(game_domain_name: @game_domain_name, mod_id: @mod_id)
  @api_client.api_cache_timestamp("games/#{game_domain_name}/mods/#{mod_id}/files")
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



259
260
261
262
263
264
265
266
267
# File 'lib/nexus_mods.rb', line 259

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(
      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 a mod files information

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



280
281
282
# File 'lib/nexus_mods.rb', line 280

def updated_mods_cache_timestamp(game_domain_name: @game_domain_name, since: :one_day)
  @api_client.api_cache_timestamp("games/#{game_domain_name}/mods/updated", parameters: period_to_url_params(since))
end