2025-08-03 00:40:34 +02:00
Metadata-Version: 2.4
2024-12-02 17:41:02 +01:00
Name: devranta
2025-08-03 00:40:34 +02:00
Version: 1.1.0
2024-12-02 17:41:02 +01:00
Summary: Async devRant API client made with aiohttp.
Author: retoor
Author-email: retoor@molodetz.nl
License: MIT
Requires-Python: >=3.7
Description-Content-Type: text/markdown
Requires-Dist: requests
Requires-Dist: aiohttp
Requires-Dist: dataset
2024-12-02 17:50:25 +01:00
# devRanta
2025-08-03 00:40:34 +02:00
devRanta is the best async devRant client written in Python. Authentication is only needed for half of the functionality; thus, the username and password are optional parameters when constructing the main class of this package (Api). You can find the latest packages in tar and wheel format [here](https://retoor.molodetz.nl/retoor/devranta/packages).
2024-12-02 17:50:25 +01:00
## Running
```
make run
```
## Testing
Tests are only made for methods not requireing authentication.
I do not see value in mocking requests.
```
make test
```
## How to use
Implementation:
```
2025-09-01 18:39:03 +02:00
from devranta.api import Api
2024-12-02 17:50:25 +01:00
api = Api(username="optional!", password="optional!")
async def list_rants():
async for rant in api.get_rants():
print(rant["user_username"], ":", rant["text"])
```
2025-09-01 18:39:03 +02:00
See [tests](src/devranta/tests.py) for [examples](src/devranta/tests.py) on how to use.
2025-08-03 00:40:34 +02:00
# devRant API Documentation
For people wanting to build their own client.
TODO: document responses.
## Base URL
`https://devrant.com/api`
## Authentication
- Uses `dr_token` cookie with `token_id`, `token_key`, and `user_id`.
- Required for endpoints needing user authentication.
- `guid`, `plat`, `sid`, `seid` included in requests for session tracking.
## Endpoints
### User Management
2025-09-01 18:39:03 +02:00
1. **Registering user**
- Ommitted, you know why.
2025-08-03 00:40:34 +02:00
2. **Login User**
- **URL**: `/api/users/auth-token`
- **Method**: POST
- **Parameters**:
- `app`: 3
- `username`: User username
- `password`: User password
- `guid`: Unique identifier
- `plat`: 3
- `sid`: Session start time
- `seid`: Session event ID
- **Response**: JSON with `success`, `auth_token`, or `error`
2025-09-01 18:39:03 +02:00
- **Success Example**:
```json
{
"success": true,
"auth_token": {
"id": 18966518,
"key": "z6uXRZrQ_Ekx59wfYEjpbnS!fDeVznVqmmKujhT8",
"expire_time": 1756765587,
"user_id": 18959632
}
}
```
- **Error Example**:
```json
{
"success": false,
"error": "Invalid login credentials entered. Please try again."
}
```
2025-08-03 00:40:34 +02:00
- **Description**: Authenticates user and returns auth token.
3. **Edit Profile**
- **URL**: `/api/users/me/edit-profile`
- **Method**: POST
- **Parameters**:
- `app`: 3
- `token_id`: Token ID
- `token_key`: Token key
- `user_id`: User ID
- `guid`, `plat`, `sid`, `seid`
- `profile_about`: User bio
- `profile_skills`: User skills
- `profile_location`: User location
- `profile_website`: User website
- `profile_github`: GitHub username
- **Response**: JSON with `success`
2025-09-01 18:39:03 +02:00
- **Success Example**:
```json
{
"success": true
}
```
2025-08-03 00:40:34 +02:00
- **Description**: Updates user profile information.
4. **Forgot Password**
- **URL**: `/api/users/forgot-password`
- **Method**: POST
- **Parameters**:
- `app`: 3
- `username`: User username
- `guid`, `plat`, `sid`, `seid`
- **Response**: JSON with `success`
2025-09-01 18:39:03 +02:00
- **Success Example**:
```json
{
"success": true
}
```
2025-08-03 00:40:34 +02:00
- **Description**: Initiates password reset process.
5. **Resend Confirmation Email**
- **URL**: `/api/users/me/resend-confirm`
- **Method**: POST
- **Parameters**:
- `app`: 3
- `token_id`, `token_key`, `user_id`, `guid`, `plat`, `sid`, `seid`
- **Response**: JSON with `success`
2025-09-01 18:39:03 +02:00
- **Success Example**:
```json
{
"success": true
}
```
2025-08-03 00:40:34 +02:00
- **Description**: Resends account confirmation email.
6. **Delete Account**
- **URL**: `/api/users/me`
- **Method**: DELETE
- **Parameters**:
- `app`: 3
- `token_id`, `token_key`, `user_id`, `guid`, `plat`, `sid`, `seid`
- **Response**: JSON with `success`
- **Description**: Deletes user account.
7. **Mark News as Read**
- **URL**: `/api/users/me/mark-news-read`
- **Method**: POST
- **Parameters**:
- `app`: 3
- `token_id`, `token_key`, `user_id`, `guid`, `plat`, `sid`, `seid`
- `news_id`: News item ID
- **Response**: JSON with `success`
2025-09-01 18:39:03 +02:00
- **Success Example**:
```json
{
"success": true
}
```
2025-08-03 00:40:34 +02:00
- **Description**: Marks a news item as read for logged-in users.
### Rants
1. **Get Rant**
- **URL**: `/api/devrant/rants/{rant_id}`
- **Method**: GET
- **Parameters**:
- `app`: 3
- `token_id`, `token_key`, `user_id`, `guid`, `plat`, `sid`, `seid`
- `last_comment_id`: 999999999999 (optional)
- `links`: 0 (optional)
2025-09-01 18:39:03 +02:00
- **Response**: JSON with `rant` (text, tags), `comments`, `success`, `subscribed`
- **Success Example**:
```json
{
"rant": {
"id": 18960811,
"text": "You know, I'm getting tired of this HR-speak in job applications, specifically this:\n\n- [tech] has no secrets for you\n\nWhat, really? So I am the undisputed and absolute expert of - let's say - JavaScript? Do you know how long it takes to master that so that it holds no secrets? It even holds secrets to decade-long experts! The same goes for most other technologies in software development.\n\nSigh. Hhhhh. Ree.",
"score": 3,
"created_time": 1754065322,
"attached_image": "",
"num_comments": 10,
"tags": [
"too-much",
"qualifications",
"job-hunting"
],
"vote_state": 0,
"edited": false,
"link": "rants/18960811/you-know-im-getting-tired-of-this-hr-speak-in-job-applications-specifically-this",
"rt": 1,
"rc": 1,
"user_id": 1366654,
"user_username": "CaptainRant",
"user_score": 4179,
"user_avatar": {
"b": "2a8b9d",
"i": "v-37_c-3_b-4_g-m_9-1_1-2_16-6_3-1_8-1_7-1_5-2_12-2_6-3_10-1_2-10_22-2_11-2_18-1_19-3_4-2_20-1_21-2.jpg"
},
"user_avatar_lg": {
"b": "2a8b9d",
"i": "v-37_c-1_b-4_g-m_9-1_1-2_16-6_3-1_8-1_7-1_5-2_12-2_6-3_10-1_2-10_22-2_11-2_18-1_19-3_4-2_20-1_21-2.png"
}
},
"comments": [],
"success": true,
"subscribed": 0
}
```
2025-08-03 00:40:34 +02:00
- **Description**: Retrieves a specific rant by ID.
2. **Post Rant**
- **URL**: `/api/devrant/rants`
- **Method**: POST
- **Parameters** (FormData):
- `app`: 3
- `rant`: Rant text
- `tags`: Comma-separated tags
- `token_id`, `token_key`, `user_id`
- `type`: Rant type ID
- `image`: Optional image file (img/gif)
- **Response**: JSON with `success`, `rant_id`, or `error`
2025-09-01 18:39:03 +02:00
- **Error Example**:
```json
{
"success": false,
"error": "It looks like you just posted this same rant! Your connection might have timed out while posting so you might have seen an error, but sometimes the rant still gets posted and in this case it seems it did, so please check :) If this was not the case please contact info@devrant.io. Thanks!"
}
```
2025-08-03 00:40:34 +02:00
- **Description**: Creates a new rant.
3. **Edit Rant**
- **URL**: `/api/devrant/rants/{rant_id}`
- **Method**: POST
- **Parameters** (FormData):
- `app`: 3
- `rant`: Rant text
- `tags`: Comma-separated tags
- `token_id`, `token_key`, `user_id`
- `image`: Optional image file
- **Response**: JSON with `success` or `fail_reason`
2025-09-01 18:39:03 +02:00
- **Error Example**:
```json
{
"success": false,
"fail_reason": ""
}
```
2025-08-03 00:40:34 +02:00
- **Description**: Updates an existing rant.
4. **Delete Rant**
- **URL**: `/api/devrant/rants/{rant_id}`
- **Method**: DELETE
- **Parameters**:
- `app`: 3
- `token_id`, `token_key`, `user_id`, `guid`, `plat`, `sid`, `seid`
2025-09-01 18:39:03 +02:00
- **Response**: JSON with `success` or `error`
- **Error Example**:
```json
{
"success": false,
"error": "An unknown error occurred and this rant can't be deleted. Please contact support@devrant.com for help with this."
}
```
2025-08-03 00:40:34 +02:00
- **Description**: Deletes a rant.
5. **Vote on Rant**
- **URL**: `/api/devrant/rants/{rant_id}/vote`
- **Method**: POST
- **Parameters**:
- `app`: 3
- `token_id`, `token_key`, `user_id`, `guid`, `plat`, `sid`, `seid`
- `vote`: 1 (upvote), -1 (downvote), 0 (remove vote)
- `reason`: Downvote reason ID (required for downvote)
2025-09-01 18:39:03 +02:00
- **Response**: JSON with `success`, `rant`, or `confirmed` (false if unverified)
- **Success Example**:
```json
{
"success": true,
"rant": {
"id": 18960811,
"text": "You know, I'm getting tired of this HR-speak in job applications, specifically this:\n\n- [tech] has no secrets for you\n\nWhat, really? So I am the undisputed and absolute expert of - let's say - JavaScript? Do you know how long it takes to master that so that it holds no secrets? It even holds secrets to decade-long experts! The same goes for most other technologies in software development.\n\nSigh. Hhhhh. Ree.",
"score": 3,
"created_time": 1754065322,
"attached_image": "",
"num_comments": 10,
"tags": [
"rant",
"too-much",
"qualifications",
"job-hunting"
],
"vote_state": -1,
"edited": false,
"rt": 1,
"rc": 1,
"user_id": 1366654,
"user_username": "CaptainRant",
"user_score": 4180,
"user_avatar": {
"b": "2a8b9d",
"i": "v-37_c-3_b-4_g-m_9-1_1-2_16-6_3-1_8-1_7-1_5-2_12-2_6-3_10-1_2-10_22-2_11-2_18-1_19-3_4-2_20-1_21-2.jpg"
},
"user_avatar_lg": {
"b": "2a8b9d",
"i": "v-37_c-1_b-4_g-m_9-1_1-2_16-6_3-1_8-1_7-1_5-2_12-2_6-3_10-1_2-10_22-2_11-2_18-1_19-3_4-2_20-1_21-2.png"
}
}
}
```
2025-08-03 00:40:34 +02:00
- **Description**: Votes on a rant.
6. **Favorite/Unfavorite Rant**
- **URL**: `/api/devrant/rants/{rant_id}/{favorite|unfavorite}`
- **Method**: POST
- **Parameters**:
- `app`: 3
- `token_id`, `token_key`, `user_id`, `guid`, `plat`, `sid`, `seid`
- **Response**: JSON with `success`
2025-09-01 18:39:03 +02:00
- **Success Example**:
```json
{
"success": true
}
```
2025-08-03 00:40:34 +02:00
- **Description**: Favorites or unfavorites a rant.
7. **Get Rant Feed**
- **URL**: `/api/devrant/rants`
- **Method**: GET
- **Parameters**:
- `app`: 3
- `token_id`, `token_key`, `user_id`, `guid`, `plat`, `sid`, `seid`
- `ids`: JSON string of IDs (optional)
2025-09-01 18:39:03 +02:00
- **Response**: JSON with `success`, `rants`, `settings`, `set`, `wrw`, `dpp`, `num_notifs`, `unread`, `news`
- **Success Example**:
```json
{
"success": true,
"rants": [
{
"id": 18960811,
"text": "You know, I'm getting tired of this HR-speak in job applications, specifically this:\n\n- [tech] has no secrets for you\n\nWhat, really? So I am the undisputed and absolute expert of - let's say - JavaScript? Do you know how long it takes to master that so that it holds no secrets? It even holds secrets to decade-long experts! The same goes for most other technologies in software development.\n\nSigh. Hhhhh. Ree.",
"score": 3,
"created_time": 1754065322,
"attached_image": "",
"num_comments": 9,
"tags": [
"rant",
"too-much",
"qualifications",
"job-hunting"
],
"vote_state": 0,
"edited": false,
"rt": 1,
"rc": 1,
"user_id": 1366654,
"user_username": "CaptainRant",
"user_score": 4179,
"user_avatar": {
"b": "2a8b9d",
"i": "v-37_c-3_b-4_g-m_9-1_1-2_16-6_3-1_8-1_7-1_5-2_12-2_6-3_10-1_2-10_22-2_11-2_18-1_19-3_4-2_20-1_21-2.jpg"
},
"user_avatar_lg": {
"b": "2a8b9d",
"i": "v-37_c-1_b-4_g-m_9-1_1-2_16-6_3-1_8-1_7-1_5-2_12-2_6-3_10-1_2-10_22-2_11-2_18-1_19-3_4-2_20-1_21-2.png"
}
}
// ... more rants
],
"settings": {
"notif_state": -1,
"notif_token": ""
},
"set": "688e90b7cf77f",
"wrw": 385,
"dpp": 0,
"num_notifs": 0,
"unread": {
"total": 0
},
"news": {
"id": 356,
"type": "intlink",
"headline": "Weekly Group Rant",
"body": "Tips for staying productive?",
"footer": "Add tag 'wk247' to your rant",
"height": 100,
"action": "grouprant"
}
}
```
2025-08-03 00:40:34 +02:00
- **Description**: Retrieves rant feed with notification count.
### Comments
1. **Get Comment**
- **URL**: `/api/comments/{comment_id}`
- **Method**: GET
- **Parameters**:
- `app`: 3
- `token_id`, `token_key`, `user_id`, `guid`, `plat`, `sid`, `seid`
- `links`: 0 (optional)
2025-09-01 18:39:03 +02:00
- **Response**: JSON with `comment` (body), or `error`
- **Error Example**:
```json
{
"success": false,
"error": "Invalid comment specified in path."
}
```
2025-08-03 00:40:34 +02:00
- **Description**: Retrieves a specific comment by ID.
2. **Post Comment**
- **URL**: `/api/devrant/rants/{rant_id}/comments`
- **Method**: POST
- **Parameters** (FormData):
- `app`: 3
- `comment`: Comment text
- `token_id`, `token_key`, `user_id`
- `image`: Optional image file (img/gif)
- **Response**: JSON with `success` or `confirmed` (false if unverified)
2025-09-01 18:39:03 +02:00
- **Success Example**:
```json
{
"success": true
}
```
2025-08-03 00:40:34 +02:00
- **Description**: Posts a comment on a rant.
3. **Edit Comment**
- **URL**: `/api/comments/{comment_id}`
- **Method**: POST
- **Parameters** (FormData):
- `app`: 3
- `comment`: Comment text
- `token_id`, `token_key`, `user_id`
- **Response**: JSON with `success` or `fail_reason`
2025-09-01 18:39:03 +02:00
- **Error Example**:
```json
{
"success": false,
"error": "Invalid comment specified in path."
}
```
2025-08-03 00:40:34 +02:00
- **Description**: Updates an existing comment.
4. **Delete Comment**
- **URL**: `/api/comments/{comment_id}`
- **Method**: DELETE
- **Parameters**:
- `app`: 3
- `token_id`, `token_key`, `user_id`, `guid`, `plat`, `sid`, `seid`
2025-09-01 18:39:03 +02:00
- **Response**: JSON with `success` or `error`
- **Error Example**:
```json
{
"success": false,
"error": "Invalid comment specified in path."
}
```
2025-08-03 00:40:34 +02:00
- **Description**: Deletes a comment.
5. **Vote on Comment**
- **URL**: `/api/comments/{comment_id}/vote`
- **Method**: POST
- **Parameters**:
- `app`: 3
- `token_id`, `token_key`, `user_id`, `guid`, `plat`, `sid`, `seid`
- `vote`: 1 (upvote), -1 (downvote), 0 (remove vote)
- `reason`: Downvote reason ID (required for downvote)
2025-09-01 18:39:03 +02:00
- **Response**: JSON with `success` or `error`
- **Error Example**:
```json
{
"success": false,
"error": "Invalid comment specified in path."
}
```
2025-08-03 00:40:34 +02:00
- **Description**: Votes on a comment.
### Notifications
1. **Get Notification Feed**
- **URL**: `/api/users/me/notif-feed`
- **Method**: GET
- **Parameters**:
- `app`: 3
- `token_id`, `token_key`, `user_id`, `guid`, `plat`, `sid`, `seid`
- `ext_prof`: 1 (optional)
- `last_time`: Last notification check time
2025-09-01 18:39:03 +02:00
- **Response**: JSON with `success`, `data` (items, check_time, username_map, unread, num_unread)
- **Success Example**:
```json
{
"success": true,
"data": {
"items": [],
"check_time": 1754173634,
"username_map": [],
"unread": {
"all": 0,
"upvotes": 0,
"mentions": 0,
"comments": 0,
"subs": 0,
"total": 0
},
"num_unread": 0
}
}
```
2025-08-03 00:40:34 +02:00
- **Description**: Retrieves user notifications.
2. **Clear Notifications**
- **URL**: `/api/users/me/notif-feed`
- **Method**: DELETE
- **Parameters**:
- `app`: 3
- `token_id`, `token_key`, `user_id`, `guid`, `plat`, `sid`, `seid`
- **Response**: JSON with `success`
2025-09-01 18:39:03 +02:00
- **Success Example**:
```json
{
"success": true
}
```
2025-08-03 00:40:34 +02:00
- **Description**: Clears user notifications.
2025-09-01 18:39:03 +02:00
### External API
2025-08-03 00:40:34 +02:00
- **Beta List Signup**
- **URL**: `https://www.hexicallabs.com/api/beta-list`
- **Method**: GET (JSONP)
- **Parameters**:
- `email`: User email
- `platform`: Platform name
- `app`: 3
2025-09-01 18:39:03 +02:00
- **Response**: JSON with `error`
- **Error Example**:
```json
{
"error": "Expecting value: line 1 column 1 (char 0)"
}
```
2025-08-03 00:40:34 +02:00
- **Description**: Signs up user for beta list (external service).
## Notes
- All endpoints expect `app=3` for identification.
- Authenticated endpoints require `dr_token` cookie with `token_id`, `token_key`, `user_id`.
- `guid`, `plat`, `sid`, `seid` are used for session tracking.
- Image uploads use FormData for rants and comments.
- Downvotes require a reason ID, prompting a modal if not provided.
- Responses typically include `success` boolean; errors include `error` or `fail_reason`.
- Cookies (`dr_token`, `dr_guid`, `dr_session_start`, `dr_event_id`, `dr_feed_sort`, `dr_theme`, `dr_rants_viewed`, `dr_stickers_seen`, `rant_type_filters`, `news_seen`) manage state and preferences.