Skip to content

Commit b1a38f7

Browse files
committed
Merge branch 'development' into main
2 parents a4af01c + ca940a0 commit b1a38f7

File tree

5 files changed

+55
-27
lines changed

5 files changed

+55
-27
lines changed

src/api/cfclient.nim

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,43 @@
1-
## Provides functions for connecting to the unofficial curseforge api.
1+
## Provides functions for connecting to the CF proxy [https://github.com/bmpm-mc/cfproxy].
22
##
3-
## The unofficial API has capabilities like:
3+
## The proxy connects to the official API internally, and has capabilities like:
44
## - Searching for a addon.
55
## - Retrieving an addon by their project id.
66
## - Retrieving the files of an given addon.
77
##
8-
## Some docs for the unofficial API are available at https://gaz492.github.io/.
8+
## Docs for the official API are available at https://docs.curseforge.com.
9+
## Requests to the proxy stay the same, except the base URL is switched out.
910

1011
import asyncdispatch, json, options, strutils
1112
import uri except Url
1213
import cfcore, http
1314

1415
const
15-
## base url of the forgesvc endpoint
16-
addonsBaseUrl = "https://addons-ecs.forgesvc.net/api/v2"
16+
## base url of the cfproxy endpoint
17+
addonsBaseUrl = "https://cfproxy.fly.dev"
1718
## base url of the curse metadata api endpoint
1819
## used for retrieving mods by their slug, which isn't possible with the curse api
1920
addonsSlugBaseUrl = "https://curse.nikky.moe/graphql"
2021

21-
proc fetchAddonsByQuery*(query: string, category = CfAddonGameCategory.Mod): Future[seq[CfAddon]] {.async.} =
22+
proc fetchAddonsByQuery*(query: string, category: Option[CfAddonGameCategory]): Future[seq[CfAddon]] {.async.} =
2223
## retrieves all addons that match the given `query` search and `category`.
2324
let encodedQuery = encodeUrl(query, usePlus = false)
24-
let url = addonsBaseUrl & "/addon/search?gameId=432&sectionId=" & $category & "&pageSize=50&searchFilter=" & encodedQuery
25+
var url = addonsBaseUrl & "/v1/mods/search?gameId=432&pageSize=50&sortField=6&sortOrder=desc&searchFilter=" & encodedQuery
26+
if category.isSome:
27+
url = url & "&classId=" & $ord(category.get())
2528
try:
26-
return get(url.Url).await.parseJson.addonsFromForgeSvc
29+
return get(url.Url).await.parseJson["data"].addonsFromForgeSvc
2730
except HttpRequestError:
2831
return @[]
2932

33+
proc fetchAddonsByQuery*(query: string): Future[seq[CfAddon]] {.async.} =
34+
return await fetchAddonsByQuery(query, category = none[CfAddonGameCategory]())
35+
3036
proc fetchAddon*(projectId: int): Future[Option[CfAddon]] {.async.} =
3137
## get the addon with the given `projectId`.
32-
let url = addonsBaseUrl & "/addon/" & $projectId
38+
let url = addonsBaseUrl & "/v1/mods/" & $projectId
3339
try:
34-
return get(url.Url).await.parseJson.addonFromForgeSvc.some
40+
return get(url.Url).await.parseJson["data"].addonFromForgeSvc.some
3541
except HttpRequestError:
3642
return none[CfAddon]()
3743
@@ -53,16 +59,16 @@ proc fetchAddon*(slug: string): Future[Option[CfAddon]] {.async.} =
5359
5460
proc fetchAddonFiles*(projectId: int): Future[seq[CfAddonFile]] {.async.} =
5561
## get all addon files associated with the given `projectId`.
56-
let url = addonsBaseUrl & "/addon/" & $projectId & "/files"
62+
let url = addonsBaseUrl & "/v1/mods/" & $projectId & "/files?pageSize=10000"
5763
try:
58-
return get(url.Url).await.parseJson.addonFilesFromForgeSvc
64+
return get(url.Url).await.parseJson["data"].addonFilesFromForgeSvc
5965
except HttpRequestError:
6066
return @[]
6167

6268
proc fetchAddonFile*(projectId: int, fileId: int): Future[Option[CfAddonFile]] {.async.} =
6369
## get the addon file with the given `fileId` & `projectId`.
64-
let url = addonsBaseUrl & "/addon/" & $projectId & "/file/" & $fileId
70+
let url = addonsBaseUrl & "/v1/mods/" & $projectId & "/files/" & $fileId
6571
try:
66-
return get(url.Url).await.parseJson.addonFileFromForgeSvc.some
72+
return get(url.Url).await.parseJson["data"].addonFileFromForgeSvc.some
6773
except HttpRequestError:
6874
return none[CfAddonFile]()

src/api/cfcore.nim

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,11 @@ converter addonFileFromForgeSvc*(json: JsonNode): CfAddonFile =
4949
result.name = json["displayName"].getStr()
5050
result.releaseType = json["releaseType"].getInt().CfAddonFileReleaseType
5151
result.downloadUrl = json["downloadUrl"].getStr()
52-
result.gameVersions = json["gameVersion"].getElems().map((x) => x.getStr().Version)
52+
result.gameVersions = json["gameVersions"].getElems().map((x) => x.getStr().Version)
5353
result.dependencies = collect(newSeq):
5454
for depends in json["dependencies"].getElems():
55-
if depends["type"].getInt() == RequiredDependencyType:
56-
depends["addonId"].getInt()
55+
if depends["relationType"].getInt() == RequiredDependencyType:
56+
depends["modId"].getInt()
5757

5858
converter addonFilesFromForgeSvc*(json: JsonNode): seq[CfAddonFile] =
5959
## creates addon files from json retrieved by an forgesvc endpoint
@@ -65,15 +65,15 @@ converter addonFromForgeSvc*(json: JsonNode): CfAddon =
6565
result.projectId = json["id"].getInt()
6666
result.name = json["name"].getStr()
6767
result.description = json["summary"].getStr()
68-
result.websiteUrl = json["websiteUrl"].getStr()
68+
result.websiteUrl = json["links"]{"websiteUrl"}.getStr()
6969
result.authors = json["authors"].getElems().map((x) => x["name"].getStr())
7070
result.downloads = json["downloadCount"].getFloat().int
71-
result.popularity = json["popularityScore"].getFloat()
71+
result.popularity = json["gamePopularityRank"].getFloat()
7272
result.latestFiles = json["latestFiles"].getElems().map(addonFileFromForgeSvc)
7373
result.gameVersionLatestFiles = collect(newSeq):
74-
for file in json["gameVersionLatestFiles"].getElems():
74+
for file in json["latestFilesIndexes"].getElems():
7575
let version = file["gameVersion"].getStr().Version
76-
let fileId = file["projectFileId"].getInt()
76+
let fileId = file["fileId"].getInt()
7777
(version: version, fileId: fileId)
7878

7979
converter addonsFromForgeSvc*(json: JsonNode): seq[CfAddon] =

src/cmd/add.nim

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ proc strScan(input: string, strVal: var string, start: int): int =
3838
inc result
3939
strVal = input.substr(start, start+result-1)
4040

41-
proc paxAdd*(input: string, noDepends: bool, strategy: string): void =
41+
proc paxAdd*(input: string, noDepends: bool, strategy: string, addonType: string): void =
4242
## add a new mod
4343
requirePaxProject()
4444

@@ -116,7 +116,14 @@ proc paxAdd*(input: string, noDepends: bool, strategy: string): void =
116116

117117
else:
118118
## Just search normally
119-
let mcMods = waitFor(fetchAddonsByQuery(input))
119+
let addonType: Option[CfAddonGameCategory] = case addonType:
120+
of "mod":
121+
some(CfAddonGameCategory.Mod)
122+
of "resourcepack":
123+
some(CfAddonGameCategory.Resourcepack)
124+
else:
125+
none[CfAddonGameCategory]()
126+
let mcMods = waitFor(fetchAddonsByQuery(input, addonType))
120127
let mcModOption = manifest.promptAddonChoice(mcMods, selectInstalled = false)
121128
if mcModOption.isNone:
122129
echoError "No mods found for your search."

src/pax.nim

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@ let addCmd = (
6060
noDepends: newCountArg(@["--no-deps"],
6161
help = "don't install dependencies"
6262
),
63+
addonType: newStringArg(@["-t", "--type"],
64+
choices = @["mod", "resourcepack"],
65+
help = "restrict search to a certain addon type"
66+
),
6367
strategy: commonArgs.strategy,
6468
yes: commonArgs.yes,
6569
noColor: commonArgs.noColor,
@@ -209,8 +213,12 @@ if spec.init.seen:
209213
elif spec.list.seen:
210214
paxList(status = listCmd.status.seen, info = listCmd.info.seen)
211215
elif spec.add.seen:
212-
paxAdd(input = addCmd.input.value, noDepends = addCmd.noDepends.seen,
213-
strategy = addCmd.strategy.value)
216+
paxAdd(
217+
input = addCmd.input.value,
218+
noDepends = addCmd.noDepends.seen,
219+
strategy = addCmd.strategy.value,
220+
addonType = addCmd.addonType.value
221+
)
214222
elif spec.remove.seen:
215223
paxRemove(name = removeCmd.name.value, strategy = removeCmd.strategy.value)
216224
elif spec.pin.seen:

tests/api/tcfclient.nim

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,23 @@
11
discard """
22
cmd: "nim $target --hints:on -d:testing -d:ssl --nimblePath:tests/deps $options $file"
3-
disabled: "win"
43
"""
54

6-
import asyncdispatch, options, sequtils, sugar
5+
import asyncdispatch, options, sequtils, strutils, sugar
76
import api/cfclient, api/cfcore
87

98
block: # fetch by query
109
let mods = waitFor(fetchAddonsByQuery("jei"))
1110
doAssert mods[0].projectId == 238222
1211
doAssert mods[0].name == "Just Enough Items (JEI)"
1312

13+
block: # fetch mods by query
14+
let mods = waitFor(fetchAddonsByQuery("jei", some(CfAddonGameCategory.Mod)))
15+
doAssert mods.all(m => m.websiteUrl.contains("/mc-mods/"))
16+
17+
block: # fetch resource packs by query
18+
let mods = waitFor(fetchAddonsByQuery("jei", some(CfAddonGameCategory.Resourcepack)))
19+
doAssert mods.all(m => m.websiteUrl.contains("/texture-packs/"))
20+
1421
block: # fetch mod by id
1522
let mcMod = waitFor(fetchAddon(220318)).get()
1623
doAssert mcMod.projectId == 220318

0 commit comments

Comments
 (0)