diff --git a/src/main/kotlin/top/jie65535/jcf/CurseforgeApi.kt b/src/main/kotlin/top/jie65535/jcf/CurseforgeApi.kt index 4845255..008a446 100644 --- a/src/main/kotlin/top/jie65535/jcf/CurseforgeApi.kt +++ b/src/main/kotlin/top/jie65535/jcf/CurseforgeApi.kt @@ -7,11 +7,16 @@ import io.ktor.client.request.* import io.ktor.http.* import kotlinx.serialization.* import kotlinx.serialization.json.Json +import top.jie65535.jcf.model.Category +import top.jie65535.jcf.model.file.File import top.jie65535.jcf.model.mod.* import top.jie65535.jcf.model.request.* import top.jie65535.jcf.model.request.SortOrder.* import top.jie65535.jcf.model.response.* +/** + * [Api docs](https://docs.curseforge.com/) + */ @OptIn(ExperimentalSerializationApi::class) class CurseforgeApi(apiKey: String) { companion object { @@ -23,6 +28,7 @@ class CurseforgeApi(apiKey: String) { ignoreUnknownKeys = true serializersModule } + private val http = HttpClient(OkHttp) { install(HttpTimeout) { this.requestTimeoutMillis = 30_0000 @@ -37,7 +43,32 @@ class CurseforgeApi(apiKey: String) { } } - //region Mods + //region - Game - + + // Minecraft Game ID is 432 + // Ignore Game APIs + + //endregion + + //region - Categories - + + /** + * Get all available classes and categories of the specified game. + * Specify a game id for a list of all game categories, + * or a class id for a list of categories under that class. + */ + suspend fun getCategories(gameId: Int, classId: Int?): Array { + return json.decodeFromString( + http.get("/v1/categories") { + parameter("gameId", gameId) + parameter("classId", classId) + } + ).data + } + + //endregion + + //region - Mods - /** * Get all mods that match the search criteria. @@ -93,21 +124,21 @@ class CurseforgeApi(apiKey: String) { /** * Get a single mod. */ - suspend fun getMod(modId: Int): GetModResponse { - return json.decodeFromString( + suspend fun getMod(modId: Int): Mod { + return json.decodeFromString( http.get("/v1/mods/$modId") - ) + ).data } /** * Get a list of mods. */ - suspend fun getMods(modIds: IntArray): GetModsResponse { - return json.decodeFromString( - http.get("/v1/mods") { + suspend fun getMods(modIds: IntArray): Array { + return json.decodeFromString( + http.post("/v1/mods") { body = json.encodeToString(GetModsByIdsListRequestBody(modIds)) } - ) + ).data } /** @@ -117,21 +148,86 @@ class CurseforgeApi(apiKey: String) { gameId: Int, excludedModIds: IntArray, gameVersionTypeId: Int? - ): GetFeaturedModsResponse { - return json.decodeFromString( + ): FeaturedModsResponse { + return json.decodeFromString( http.get("/v1/mods/featured") { body = json.encodeToString(GetFeaturedModsRequestBody(gameId, excludedModIds, gameVersionTypeId)) } - ) + ).data } /** * Get the full description of a mod in HTML format. */ suspend fun getModDescription(modId: Int): String { - return http.get("/v1/mods/$modId/description") + return json.decodeFromString( + http.get("/v1/mods/$modId/description") + ).data } //endregion + //region - Files - + + /** + * Get a single file of the specified mod. + */ + suspend fun getModFile(modId: Int, fileId: Int): File { + return json.decodeFromString( + http.get("/v1/mods/$modId/files/$fileId") + ).data + } + + /** + * Get all files of the specified mod. + */ + suspend fun getModFiles( + modId: Int, + gameVersion: String?, + modLoaderType: ModLoaderType?, + gameVersionTypeId: Int?, + index: Int?, + pageSize: Int? + ): GetModFilesResponse { + return json.decodeFromString( + http.get("/v1/mods/$modId/files") { + parameter("gameVersion", gameVersion) + parameter("modLoaderType", modLoaderType) + parameter("gameVersionTypeId", gameVersionTypeId) + parameter("index", index) + parameter("pageSize", pageSize) + } + ) + } + + /** + * Get a list of files. + */ + suspend fun getFiles(fileIds: IntArray): Array { + return json.decodeFromString( + http.post("/v1/mods/files") { + body = json.encodeToString(GetModFilesRequestBody(fileIds)) + } + ).data + } + + /** + * Get the changelog of a file in HTML format + */ + suspend fun getModFileChangelog(modId: Int, fileId: Int): String { + return json.decodeFromString( + http.get("/v1/mods/$modId/files/$fileId/changelog") + ).data + } + + /** + * Get a download url for a specific file + */ + suspend fun getModFileDownloadURL(modId: Int, fileId: Int): String { + return json.decodeFromString( + http.get("/v1/mods/$modId/files/$fileId/download-url") + ).data + } + + //endregion } \ No newline at end of file diff --git a/src/main/kotlin/top/jie65535/jcf/model/request/GetModFilesRequestBody.kt b/src/main/kotlin/top/jie65535/jcf/model/request/GetModFilesRequestBody.kt new file mode 100644 index 0000000..043f909 --- /dev/null +++ b/src/main/kotlin/top/jie65535/jcf/model/request/GetModFilesRequestBody.kt @@ -0,0 +1,6 @@ +package top.jie65535.jcf.model.request + +@kotlinx.serialization.Serializable +class GetModFilesRequestBody( + val fileIds: IntArray +) \ No newline at end of file diff --git a/src/main/kotlin/top/jie65535/jcf/model/response/GetCategoriesResponse.kt b/src/main/kotlin/top/jie65535/jcf/model/response/GetCategoriesResponse.kt new file mode 100644 index 0000000..3bd9b20 --- /dev/null +++ b/src/main/kotlin/top/jie65535/jcf/model/response/GetCategoriesResponse.kt @@ -0,0 +1,8 @@ +package top.jie65535.jcf.model.response + +import top.jie65535.jcf.model.Category + +@kotlinx.serialization.Serializable +class GetCategoriesResponse( + val data: Array +) \ No newline at end of file diff --git a/src/main/kotlin/top/jie65535/jcf/model/response/GetFilesResponse.kt b/src/main/kotlin/top/jie65535/jcf/model/response/GetFilesResponse.kt new file mode 100644 index 0000000..0e9ffb2 --- /dev/null +++ b/src/main/kotlin/top/jie65535/jcf/model/response/GetFilesResponse.kt @@ -0,0 +1,8 @@ +package top.jie65535.jcf.model.response + +import top.jie65535.jcf.model.file.File + +@kotlinx.serialization.Serializable +class GetFilesResponse( + val data: Array +) \ No newline at end of file diff --git a/src/main/kotlin/top/jie65535/jcf/model/response/GetModFileResponse.kt b/src/main/kotlin/top/jie65535/jcf/model/response/GetModFileResponse.kt new file mode 100644 index 0000000..f15603c --- /dev/null +++ b/src/main/kotlin/top/jie65535/jcf/model/response/GetModFileResponse.kt @@ -0,0 +1,8 @@ +package top.jie65535.jcf.model.response + +import top.jie65535.jcf.model.file.File + +@kotlinx.serialization.Serializable +class GetModFileResponse( + val data: File +) diff --git a/src/main/kotlin/top/jie65535/jcf/model/response/GetModFilesResponse.kt b/src/main/kotlin/top/jie65535/jcf/model/response/GetModFilesResponse.kt new file mode 100644 index 0000000..eacb1e3 --- /dev/null +++ b/src/main/kotlin/top/jie65535/jcf/model/response/GetModFilesResponse.kt @@ -0,0 +1,10 @@ +package top.jie65535.jcf.model.response + +import top.jie65535.jcf.model.Pagination +import top.jie65535.jcf.model.file.File + +@kotlinx.serialization.Serializable +class GetModFilesResponse( + val data: Array, + val pagination: Pagination +) diff --git a/src/main/kotlin/top/jie65535/jcf/model/response/StringResponse.kt b/src/main/kotlin/top/jie65535/jcf/model/response/StringResponse.kt new file mode 100644 index 0000000..77b23b9 --- /dev/null +++ b/src/main/kotlin/top/jie65535/jcf/model/response/StringResponse.kt @@ -0,0 +1,6 @@ +package top.jie65535.jcf.model.response + +@kotlinx.serialization.Serializable +class StringResponse( + val data: String +) \ No newline at end of file