|
| 1 | +from typing import Optional, Union, List |
| 2 | +from enum import Enum |
| 3 | +import json |
| 4 | + |
| 5 | +from curseforge_api_wrapper.models import ( |
| 6 | + Mod, |
| 7 | + File, |
| 8 | + Fingerprint, |
| 9 | + Category, |
| 10 | + SearchResult, |
| 11 | + FingerprintResult, |
| 12 | + ModFilesResult, |
| 13 | +) |
| 14 | +from curseforge_api_wrapper.network import request |
| 15 | + |
| 16 | + |
| 17 | +class ModLoaderType(Enum): |
| 18 | + """ |
| 19 | + ModLoaderType |
| 20 | +
|
| 21 | + 0=Any |
| 22 | + 1=Forge |
| 23 | + 2=Cauldron |
| 24 | + 3=LiteLoader |
| 25 | + 4=Fabric |
| 26 | + 5=Quilt |
| 27 | + 6=NeoForge |
| 28 | + """ |
| 29 | + |
| 30 | + Any = 0 |
| 31 | + Forge = 1 |
| 32 | + Cauldron = 2 |
| 33 | + LiteLoader = 3 |
| 34 | + Fabric = 4 |
| 35 | + Quilt = 5 |
| 36 | + NeoForge = 6 |
| 37 | + |
| 38 | + |
| 39 | +class ModsSearchSortField(Enum): |
| 40 | + Featured = 1 |
| 41 | + Popularity = 2 |
| 42 | + LastUpdated = 3 |
| 43 | + Name = 4 |
| 44 | + Author = 5 |
| 45 | + TotalDownloads = 6 |
| 46 | + Category = 7 |
| 47 | + GameVersion = 8 |
| 48 | + EarlyAccess = 9 |
| 49 | + FeaturedReleased = 10 |
| 50 | + ReleasedDate = 11 |
| 51 | + Rating = 12 |
| 52 | + |
| 53 | + |
| 54 | +class SortOrder(Enum): |
| 55 | + Asc = "asc" |
| 56 | + Desc = "desc" |
| 57 | + |
| 58 | + |
| 59 | +class Client: |
| 60 | + def __init__(self, api_key: str, endpoint: str = "https://api.curseforge.com"): |
| 61 | + self.api_key = api_key |
| 62 | + self.headers = {"x-api-key": api_key, "Accept": "application/json", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36 Edg/116.0.1938.54"} |
| 63 | + self.endpoint = endpoint |
| 64 | + |
| 65 | + def search_mods( |
| 66 | + self, |
| 67 | + gameId: int, |
| 68 | + classId: Optional[int] = None, |
| 69 | + categoryId: Optional[int] = None, |
| 70 | + categoryIds: Optional[str] = None, |
| 71 | + gameVersion: Optional[str] = None, |
| 72 | + gameVersions: Optional[str] = None, |
| 73 | + searchFilter: Optional[str] = None, |
| 74 | + sortField: Optional[Union[int, ModsSearchSortField]] = None, |
| 75 | + sortOrder: Optional[Union[str, SortOrder]] = None, |
| 76 | + modLoaderType: Optional[Union[int, ModLoaderType]] = None, |
| 77 | + modLoaderTypes: Optional[str] = None, |
| 78 | + gameVersionTypeId: Optional[int] = None, |
| 79 | + authorId: Optional[int] = None, |
| 80 | + primaryAuthorId: Optional[int] = None, |
| 81 | + slug: Optional[str] = None, |
| 82 | + index: Optional[int] = None, |
| 83 | + pageSize: Optional[int] = None, |
| 84 | + ) -> SearchResult: |
| 85 | + url = f"{self.endpoint}/v1/mods/search" |
| 86 | + params = { |
| 87 | + "gameId": gameId, |
| 88 | + "classId": classId, |
| 89 | + "categoryId": categoryId, |
| 90 | + "categoryIds": categoryIds, |
| 91 | + "gameVersion": gameVersion, |
| 92 | + "gameVersions": gameVersions, |
| 93 | + "searchFilter": searchFilter, |
| 94 | + "sortField": ( |
| 95 | + (sortField if type(sortField) is int else sortField.value) |
| 96 | + if sortField |
| 97 | + else None |
| 98 | + ), |
| 99 | + "sortOrder": ( |
| 100 | + (sortOrder if type(sortOrder) is str else sortOrder.value) |
| 101 | + if sortOrder |
| 102 | + else None |
| 103 | + ), |
| 104 | + "modLoaderType": ( |
| 105 | + modLoaderType |
| 106 | + if type(modLoaderType) is int |
| 107 | + else modLoaderType.value if modLoaderType else None |
| 108 | + ), |
| 109 | + "modLoaderTypes": modLoaderTypes, |
| 110 | + "gameVersionTypeId": gameVersionTypeId, |
| 111 | + "authorId": authorId, |
| 112 | + "primaryAuthorId": primaryAuthorId, |
| 113 | + "slug": slug, |
| 114 | + "index": index, |
| 115 | + "pageSize": pageSize, |
| 116 | + } |
| 117 | + res = request( |
| 118 | + url, |
| 119 | + headers=self.headers, |
| 120 | + params=params, |
| 121 | + ) |
| 122 | + return SearchResult(**res) |
| 123 | + |
| 124 | + def get_mod(self, modId: int) -> Mod: |
| 125 | + url = f"{self.endpoint}/v1/mods/{modId}" |
| 126 | + res = request(url, headers=self.headers) |
| 127 | + return Mod(**res["data"]) |
| 128 | + |
| 129 | + def get_mods(self, modIds: List[int]) -> List[Mod]: |
| 130 | + url = f"{self.endpoint}/v1/mods" |
| 131 | + res = request(url, method="POST", headers=self.headers, json={"modIds": modIds}) |
| 132 | + return [Mod(**item) for item in res["data"]] |
| 133 | + |
| 134 | + def get_mod_files( |
| 135 | + self, |
| 136 | + modId: int, |
| 137 | + gameVersion: Optional[str] = None, |
| 138 | + modLoaderType: Optional[Union[int, ModLoaderType]] = None, |
| 139 | + gameVersionTypeId: Optional[int] = None, |
| 140 | + index: Optional[int] = None, |
| 141 | + pageSize: Optional[int] = None, |
| 142 | + ) -> ModFilesResult: |
| 143 | + """ |
| 144 | + Get mod files |
| 145 | + """ |
| 146 | + url = f"{self.endpoint}/v1/mods/{modId}/files" |
| 147 | + res = request( |
| 148 | + url, |
| 149 | + headers=self.headers, |
| 150 | + json={ |
| 151 | + "gameVersion": gameVersion, |
| 152 | + "modLoaderType": ( |
| 153 | + modLoaderType |
| 154 | + if type(modLoaderType) is int |
| 155 | + else modLoaderType.value if modLoaderType else None |
| 156 | + ), |
| 157 | + "gameVersionTypeId": gameVersionTypeId, |
| 158 | + "index": index, |
| 159 | + "pageSize": pageSize, |
| 160 | + }, |
| 161 | + ) |
| 162 | + return ModFilesResult(**res) |
| 163 | + |
| 164 | + def get_file(self, modId: int, fileId: int) -> File: |
| 165 | + url = f"{self.endpoint}/v1/mods/{modId}/files/{fileId}" |
| 166 | + res = request(url, headers=self.headers) |
| 167 | + return File(**res["data"]) |
| 168 | + |
| 169 | + def get_files(self, fileIds: List[int]) -> List[File]: |
| 170 | + url = f"{self.endpoint}/v1/mods/files" |
| 171 | + res = request( |
| 172 | + url, method="POST", headers=self.headers, json={"fileIds": fileIds} |
| 173 | + ) |
| 174 | + return [File(**item) for item in res["data"]] |
| 175 | + |
| 176 | + def get_file_download_url(self, modId: int, fileId: int) -> str: |
| 177 | + url = f"{self.endpoint}/v1/mods/{modId}/files/{fileId}/download-url" |
| 178 | + res = request(url, headers=self.headers) |
| 179 | + return res["data"] |
| 180 | + |
| 181 | + def get_fingerprint( |
| 182 | + self, fingerprints: List[int], gameId: Optional[int] = None |
| 183 | + ) -> Fingerprint: |
| 184 | + url = ( |
| 185 | + f"{self.endpoint}/v1/fingerprints" |
| 186 | + if not gameId |
| 187 | + else f"{self.endpoint}/v1/fingerprints/{gameId}" |
| 188 | + ) |
| 189 | + data = {"fingerprints": fingerprints} |
| 190 | + res = request(url, method="POST", headers=self.headers, json=data) |
| 191 | + return FingerprintResult(**res["data"]) |
| 192 | + |
| 193 | + |
| 194 | + def get_categories( |
| 195 | + self, |
| 196 | + gameId: int, |
| 197 | + classId: Optional[int] = None, |
| 198 | + classesOnly: Optional[bool] = False, |
| 199 | + ) -> List[Category]: |
| 200 | + url = f"{self.endpoint}/v1/categories" |
| 201 | + res = request( |
| 202 | + url, |
| 203 | + headers=self.headers, |
| 204 | + params={"gameId": gameId, "classId": classId, "classesOnly": classesOnly}, |
| 205 | + ) |
| 206 | + return [Category(**item) for item in res["data"]] |
0 commit comments