├── .gitignore ├── nimhq.nimble ├── LICENSE ├── README.md └── src ├── nimhq └── endpoints.nim └── nimhq.nim /.gitignore: -------------------------------------------------------------------------------- 1 | nimcache/ 2 | -------------------------------------------------------------------------------- /nimhq.nimble: -------------------------------------------------------------------------------- 1 | # Package 2 | 3 | version = "0.1.0" 4 | author = "SilliBird" 5 | description = "HQ Trivia API wrapper for Nim" 6 | license = "MIT" 7 | srcDir = "src" 8 | 9 | 10 | # Dependencies 11 | 12 | requires "nim >= 0.19.2" 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 SilliBird 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # nimhq 2 | 3 | nimhq is a HQ Trivia API wrapper written in nim. 4 | 5 | ### Usage 6 | Install the package with `nimble` 7 | ```nim 8 | nimble install nimhq 9 | ``` 10 | To use nimhq, you must import both `nimhq` and `json` 11 | ```nim 12 | import nimhq, json 13 | ``` 14 | When compiling, you must define a conditional symbol of `SSL`, to enable SSL support. For example: 15 | ```sh 16 | nim c -d:SSL -r file.nim 17 | ``` 18 | 19 | ### Example Usage 20 | 21 | Creating a new hqClient to interface with the API 22 | ```nim 23 | let client = hqClient(loginToken="ac4321NGx06pCFVHZEfSmD4k5caYE3NbR8utLrvduGJPYGTpkoctVdMGukC5VMFF") 24 | ``` 25 | Displaying the schedule 26 | ```nim 27 | echo client.schedule() 28 | ``` 29 | Changing a username 30 | ```nim 31 | discard(client.changeUsername("ExampleUsername123")) 32 | ``` 33 | 34 | ### A note on Nim Limitations 35 | 36 | This wrapper was originally inteded to use types, which, for example, would have changed `echo client["accessToken"]` to `echo client.accessToken`. While that would be much more preferred, Nim does not *currently* support types than can vary, as parts of the HQ Trivia API change the type of data they return. As such, using `JsonNode`'s was the best possible solution, despite being the less desirable one. If Nim adds support for this in the future, usage of types may be revisited. 37 | 38 | 39 | License 40 | ---- 41 | 42 | MIT 43 | 44 | -------------------------------------------------------------------------------- /src/nimhq/endpoints.nim: -------------------------------------------------------------------------------- 1 | from cgi import encodeUrl 2 | 3 | var 4 | endpointBase* = "https://api-quiz.hype.space/" 5 | 6 | endpointUsers* = endpointBase & "users/" 7 | endpointMe* = endpointUsers & "me/" 8 | endpointPayouts* = endpointMe & "payouts/" 9 | endpointShows* = endpointBase & "shows/" 10 | endpointSchedule* = endpointShows & "now?type=hq" 11 | endpointAvatarURL* = endpointMe & "avatarUrl/" 12 | endpointFriends* = endpointBase & "friends/" 13 | endpointVerifications* = endpointBase & "verifications/" 14 | endpointEasterEggs* = endpointBase & "easter-eggs/" 15 | endpointAWS* = endpointBase & "credentials/s3" 16 | endpointMakeItRain* = endpointEasterEggs & "makeItRain/" 17 | endpointTokens* = endpointBase & "tokens/" 18 | endpointToken* = endpointMe & "token/" 19 | endpointGifts* = endpointBase & "gifts/" 20 | endpointDrops* = endpointGifts & "drops/" 21 | endpointDevices* = endpointMe & "devices/" 22 | 23 | endpointUser* = proc (uID: string): string = return endpointUsers & uID & "/" 24 | endpointClaim* = proc (gID: string): string = return endpointDrops & gID & "/claims" 25 | endpointFriend* = proc (uID: string): string = return endpointFriends & uID & "/" 26 | endpointDocuments* = proc (uID: string): string = return endpointUsers & uID & "/payouts/documents" 27 | endpointFriendRequest* = proc (uID: string): string = return endpointFriend(uID) & "requests/" 28 | endpointSearchUser* = proc (query: string): string = return endpointUsers & "?q=" & encodeUrl(query) -------------------------------------------------------------------------------- /src/nimhq.nim: -------------------------------------------------------------------------------- 1 | import httpclient, json, nimhq/endpoints 2 | 3 | ## Due to limitations of Nim, typed responses cannot be used. 4 | ## Instead, most functions return a JsonNode. 5 | 6 | proc request (a: JsonNode, requestMethod: HttpMethod, urlStr: string, requestBody: JsonNode, auth: bool): JsonNode = 7 | let client = newHttpClient() 8 | client.headers = newHttpHeaders({ 9 | "Content-Type": "application/json", 10 | "x-hq-client": "iOS/1.3.29 b123", 11 | "User-Agent": "HQ-iOS/123 CFNetwork/975.0.3 Darwin/18.2.0", 12 | }) 13 | if auth: 14 | client.headers["Authorization"] = "Bearer " & a["accessToken"].getStr() 15 | let response = client.request(url = urlStr, httpMethod = requestMethod, body = $requestBody) 16 | return parseJson(response.body) 17 | 18 | proc tokens* (a: JsonNode): JsonNode = 19 | ## Returns token information for an account. 20 | let requestBody = %*{ 21 | "token": a["loginToken"] 22 | } 23 | return request(a, HttpPost, endpointTokens, requestBody, false) 24 | 25 | proc me* (a: JsonNode): JsonNode = 26 | ## Returns basic information for an account. 27 | return request(a, HttpGet, endpointMe, %*{}, true) 28 | 29 | proc payouts* (a: JsonNode): JsonNode = 30 | ## Returns an array of payouts for an account. 31 | return request(a, HttpGet, endpointPayouts, %*{}, true) 32 | 33 | proc schedule* (a: JsonNode): JsonNode = 34 | ## Returns a schedule of games accessible to an account. 35 | return request(a, HttpGet, endpointSchedule, %*{}, true) 36 | 37 | proc makeItRain* (a: JsonNode): bool = 38 | ## Performs the "swipe trick" on an account. 39 | return request(a, HttpPost, endpointMakeItRain, %*{}, true)["result"].getBool() 40 | 41 | proc refreshLogin* (a: JsonNode): JsonNode = 42 | ## Refreshes the login associated with an account. 43 | return request(a, HttpGet, endpointToken, %*{}, true) 44 | 45 | proc claim* (a: JsonNode, gID: string): bool = 46 | ## Claims a gift to an account. 47 | return request(a, HttpPost, endpointClaim(gID), %*{}, true).getBool() 48 | 49 | proc changeUsername* (a: JsonNode, username: string): JsonNode = 50 | ## Changes an accounts username. 51 | let requestBody = %*{ 52 | "username": username 53 | } 54 | return request(a, HttpPatch, endpointMe, requestBody, true) 55 | 56 | proc searchUser* (a: JsonNode, username: string): JsonNode = 57 | ## Searches for a specified username. 58 | return request(a, HttpGet, endpointSearchUser(username), %*{}, true) 59 | 60 | proc addFriend* (a: JsonNode, uID: string): bool = 61 | ## Adds a specified friend. 62 | let req = request(a, HttpPost, endpointFriendRequest(uID), %*{}, true) 63 | if req["status"].getStr() == "PENDING": 64 | return true 65 | return false 66 | 67 | proc deleteFriend* (a: JsonNode, uID: string): bool = 68 | ## Deletes a specified friend. 69 | return request(a, HttpDelete, endpointFriendRequest(uID), %*{}, true)["result"].getBool() 70 | 71 | proc requestAWS* (a: JsonNode): JsonNode = 72 | ## Returns AWS information. 73 | return request(a, HttpGet, endpointAWS, %*{}, true) 74 | 75 | proc verify* (number, verifyMethod: string): JsonNode = 76 | ## Verify a phone number via sms or call 77 | let requestBody = %*{ 78 | "method": verifyMethod, 79 | "phone": number 80 | } 81 | return request(%*{}, HttpPost, endpointVerifications, requestBody, false) 82 | 83 | proc confirm* (verificationID, code: string): JsonNode = 84 | ## Confirms a verification session 85 | let requestBody = %*{ 86 | "code": code 87 | } 88 | return request(%*{}, HttpPost, endpointVerifications & verificationID, requestBody, false) 89 | 90 | proc create* (verificationID, username, referrer, region: string): JsonNode = 91 | ## Creates an account if a user doesnt exist. 92 | let requestBody = %*{ 93 | "country": region, 94 | "verificationId": verificationId, 95 | "username": username, 96 | "language": "en", 97 | "referringUsername": referrer 98 | } 99 | return request(%*{}, HttpPost, endpointUsers, requestBody, false) 100 | 101 | proc hqClient* (loginToken: string): JsonNode = 102 | ## Initializes a specified account. 103 | var account = %*{"loginToken": loginToken} 104 | let tokens = tokens(account) 105 | account["accessToken"] = tokens["accessToken"] 106 | account["authToken"] = tokens["authToken"] 107 | account["loginToken"] = tokens["loginToken"] 108 | account["admin"] = tokens["admin"] 109 | account["guest"] = tokens["guest"] 110 | account["tester"] = tokens["tester"] 111 | let me = me(account) 112 | account["username"] = me["username"] 113 | account["userID"] = me["userId"] 114 | account["avatarURL"] = me["avatarUrl"] 115 | return account --------------------------------------------------------------------------------