Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 18 additions & 11 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,20 @@ A simple python library for interacting with the [TETR.IO](https://tetr.io/) API

## contents

- [About](#About)
- [Installation](#Installation)
- [Documentation](#Documentation)
- [Examples](#Examples)
- [Contribution](#Contribution)
- [Notice](#Notice)
- [Helpful links](#Helpful-links)
- [Tetry](#tetry)
- [contents](#contents)
- [About](#about)
- [Installation](#installation)
- [installing from pip](#installing-from-pip)
- [installing from source](#installing-from-source)
- [Documentation](#documentation)
- [Examples](#examples)
- [General api](#general-api)
- [Chat commands](#chat-commands)
- [Simple auto-host bot](#simple-auto-host-bot)
- [Contribution](#contribution)
- [Notice](#notice)
- [Helpful links](#helpful-links)

## About

Expand Down Expand Up @@ -47,15 +54,15 @@ Here you will find code examples for the library.
### General api

```python
from tetry import api
from tetry.api import records

def printRecords(username):
records = api.getRecords(username).records
def print_records(username: str):
records: dict[str, int] = records.get_records(username).records
for name, record in records.items():
print(f'{name}: {record}')

while (name := input()):
printRecords(name)
print_records(name)

```

Expand Down
8 changes: 4 additions & 4 deletions tetry/api/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from .records import getRecords
from .user import getUser
from .stream import getStream
from .news import getNews
from .records import get_records
from .user import get_user
from .stream import get_stream
from .news import get_news
26 changes: 18 additions & 8 deletions tetry/api/cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,21 @@


class Cache:
def __init__(self, data):
self.data = data
self.status = data['status']
self.cachedAt = data['cached_at']
self.expiresAt = data['cached_until']

def is_expired(self):
return time.time() > self.expiresAt
'''
Cache class for TETR.IO data.
'''

def __init__(self, data: dict) -> None:
self.data: dict = data
self.status: str = data['status']
self.cached_at: int = data['cached_at']
self.expires_at: int = data['cached_until']

def is_expired(self) -> bool:
'''
is_expired Return True if the cache has expired.

:return: True if the cache has expired.
:rtype: bool
'''
return time.time() > self.expires_at
6 changes: 3 additions & 3 deletions tetry/api/commitId.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import requests
from .urls import enviorment
from .urls import environment


def getCommit():
json = requests.get(enviorment).json()
def get_commit() -> str:
json: dict = requests.get(environment).json()
return json['signature']['commit']['id']
19 changes: 19 additions & 0 deletions tetry/api/exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
'''
Exceptions for the API.
'''


class NewsError(Exception):
pass


class RecordError(Exception):
pass


class StreamError(Exception):
pass


class UserError(Exception):
pass
31 changes: 24 additions & 7 deletions tetry/api/news.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,40 @@
import requests

from .urls import news, addParam, addQureyParam
from .urls import news, add_param, add_query_param
from .cache import Cache
from .exceptions import NewsError


class News:
def __init__(self, data):
'''
News class for TETR.IO news.
'''

def __init__(self, data: dict) -> None:
self.cache = Cache(data['cache'])
data = data['data']['news']
self.news = data
self.news: dict = data


def get_news(stream: str = None, limit=25) -> News:
'''
get_news Get news from TETR.IO news, optionally filtered by stream.

def getNews(stream=None, limit=25):
:param stream: The stream to filter news by.
Check https://tetr.io/about/api/#streamsstream, defaults to None
:type stream: str, optional
:param limit: News length limit, defaults to 25
:type limit: int, optional
:raises NewsError: Raises NewsError if the news is not found.
:return: The News object with the news data.
:rtype: News
'''
url = news
if stream:
url = addParam(url, stream)
url = addQureyParam(url, {'limit': limit})
url = add_param(url, stream)
url = add_query_param(url, {'limit': limit})
with requests.Session() as ses:
resp = ses.get(url).json()
if not resp['success']:
raise Exception(resp['error'])
raise NewsError(resp['error'])
return News(resp)
35 changes: 25 additions & 10 deletions tetry/api/records.py
Original file line number Diff line number Diff line change
@@ -1,28 +1,43 @@
import requests

from .urls import recordUrl
from .urls import record_url
from .cache import Cache
from .exceptions import RecordError


class Records:
def __init__(self, data):
'''
Records class for TETR.IO records.
Provides 40 Lines, Blitz and Zen records.
'''

def __init__(self, data: dict) -> None:
self.cache = Cache(data['cache'])
data = data['data']
self.data = data
self.zen = data['zen']
self.blitz = data['records']['blitz']
self._40l = data['records']['40l']
self.zen: dict = data['zen']
self.blitz: dict = data['records']['blitz']
self._40l: dict = data['records']['40l']
self.records = {
'40l': self._40l['record']['endcontext']['finalTime'],
'bltz': self.blitz['record']['endcontext']['score'],
'blitz': self.blitz['record']['endcontext']['score'],
'zen': self.zen['score']
}


def getRecords(name):
url = recordUrl(name.lower())
def get_records(name: str) -> Records:
'''
get_records Return records for a given player.

:param name: The name of the player.
:type name: str
:raises RecordError: Raises RecordError if the player is not found.
:return: The Records object with the records data.
:rtype: Records
'''
url = record_url(name.lower())
with requests.Session() as ses:
resp = ses.get(url).json()
resp: dict = ses.get(url).json()
if not resp['success']:
raise Exception(resp['error'])
raise RecordError(resp['error'])
return Records(resp)
21 changes: 17 additions & 4 deletions tetry/api/resolve.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,25 @@
import requests

from .urls import resolve
from .exceptions import UserError


def getId(name, token):
def get_id(name: str, token: str) -> str:
'''
get_id Get the ID of a user.

:param name: The name of the user.
:type name: str
:param token: Your bot's token.
:type token: str
:raises UserError: Raises UserError if the user is not found.
:return: The ID of the user.
:rtype: str
'''
name = name.lower()
headers = {'authorization': f'Bearer {token}'}
res = requests.get(resolve(name), headers=headers).json()
headers: dict = {'Authorization': f'Bearer {token}'}
res: requests.Response = requests.get(
resolve(name), headers=headers).json()
if not res['success']:
raise BaseException(res['errors'][0]['msg'])
raise UserError(res['errors'][0]['msg'])
return res['_id']
27 changes: 20 additions & 7 deletions tetry/api/stream.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,36 @@
from .urls import stream

import requests

from .urls import addParam
from .urls import add_param, stream
from .cache import Cache
from .exceptions import StreamError


class Stream:
def __init__(self, data):
'''
Stream class for TETR.IO streams.
'''

def __init__(self, data: dict) -> None:
self.cache = Cache(data['cache'])
data = data['data']['records']
self.news = data


def getStream(stream):
def get_stream(stream_id: str) -> Stream:
'''
get_stream Return the given Stream from TETR.IO.

:param stream_id: The id of the stream.
Check https://tetr.io/about/api/#streamsstream for more info.
:type stream_id: str
:raises StreamError: Raises StreamError if the stream is not found.
:return: The Stream object.
:rtype: Stream
'''
url = stream
url = addParam(url, stream)
url = add_param(url, stream_id)
with requests.Session() as ses:
resp = ses.get(url).json()
if not resp['success']:
raise Exception(resp['error'])
raise StreamError(resp['error'])
return Stream(resp)
16 changes: 8 additions & 8 deletions tetry/api/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,31 +6,31 @@
activity = f'{base}/general/activity'
user = f'{base}/users'
tetraLeague = f'{base}/users/lists/league'
fulltetraLeague = f'{tetraLeague}/all'
fullTetraLeague = f'{tetraLeague}/all'
xp = f'{base}/users/lists/xp'
stream = f'{base}/streams'
news = f'{base}/news'
enviorment = 'https://tetr.io/api/server/environment'
environment = 'https://tetr.io/api/server/environment'


def getRankImage(rank):
def get_rank_image(rank):
return f'https://tetr.io/res/league-ranks/{rank}.png'


def getAvatar(id):
def get_avatar(id):
return f'https://tetr.io/user-content/avatars/{id}.jpg'


def recordUrl(username):
return addParam(user, username) + '/records'
def record_url(username):
return add_param(user, username) + '/records'


def addParam(url, param):
def add_param(url, param):
url += f'/{param}'
return url


def addQureyParam(url, params):
def add_query_param(url, params):
url += f'?{urlencode(params)}'
return url

Expand Down
38 changes: 19 additions & 19 deletions tetry/api/user.py
Original file line number Diff line number Diff line change
@@ -1,40 +1,40 @@
import requests
from requests.api import head

from .records import getRecords
from .urls import addParam, addQureyParam, getAvatar, getRankImage, user
from .records import Records, get_records
from .urls import add_param, add_query_param, get_avatar, get_rank_image, user
from .cache import Cache
from .exceptions import UserError


class User:
def __init__(self, data):
def __init__(self, data: dict) -> None:
self.cache = Cache(data['cache'])
data = data['data']['user']
self.data = data
self.id = data['_id']
self.username = data['username']
self.avatarRevision = data.get('avatar_revision') or None
self.id: str = data['_id']
self.username: str = data['username']
self.avatar_revision: str | None = data.get('avatar_revision') or None
self.league = data['league']

def getPfp(self, rev=True):
url = getAvatar(self.id)
if rev and self.avatarRevision:
url = addQureyParam(url, {'rv': self.avatarRevision})
def get_pfp(self, rev: bool = True) -> str:
url = get_avatar(self.id)
if rev and self.avatar_revision:
url = add_query_param(url, {'rv': self.avatar_revision})
return url

def getRankImage(self):
return getRankImage(self.data['league']['rank'])
def get_rank_image(self) -> str:
return get_rank_image(self.data['league']['rank'])

def getRecords(self):
return getRecords(self.username)
def get_records(self) -> Records:
return get_records(self.username)


def getUser(name, token=None):
def get_user(name: str, token: str = None) -> user:
url = user
url = addParam(url, name.lower())
url = add_param(url, name.lower())
with requests.Session() as ses:
headers = {'authorization': f'Bearer {token}'} if token else None
headers = {'Authorization': f'Bearer {token}'} if token else None
resp = ses.get(url, headers=headers).json()
if not resp['success']:
raise Exception(resp['error'])
raise UserError(resp['error'])
return User(resp)
Loading