Проект переехал - https://github.com/Open-Workshop
- Backend сервер. Непосредственно общается с Steam, кэширует моды и отсылает пользователям по запросу. Кэширование нужно для минимизации обращений к серверам Valve. Так как частые запросы туда могут расцениваться сервером как бот-активность (и он будет прав). Из про кэшированных модов сервер составляет список который могут использовать сторонние приложения. Сервер не позволяет скачивать моды со Steam на прямую. Вместо этого нужно создать запрос на кеширование и после некоторое время опрашивать сервер о состоянии запроса. После мод будет добавлен в библиотеку сервера от куда его уже можно скачать.
- Telegram бот. Написаный мной бот для удобного взаимодействия пользователя с моим сервером. Выбрал этот вариант по причине легкости и (как я понимаю, правилами Telegram это не запрешено).
Адрес сервера: https://43093.zetalink.ru:8000
Нужно передать ID
мода Steam.
Если у сервера уже есть этот мод - он его отправит как ZIP
архив со сжатием ZIP_BZIP2
.
Если у сервера нет этого мода он отправит JSON
с информацией о постановке мода на скачивание.
JSON ответы:
- Успешная постановка запроса на скачивание:
{"message": "request added to queue", "error_id": 0, "unsuccessful_attempts": true / false, "updating": true / false}
HTTP code: 202
unsuccessful_attempts
- это пометка сообщает о том были ли провальные попытки скачать мод.updating
- если true - это значит, что у сервера был загружен мод, но ваш запрос спровоцировал проверку на обновление. Сервер удаляет у себя старую версию мода и начинает загрузку новой.
- Сервер запускается:
{"message": "the server is not ready to process requests", "error_id": 1}
HTTP code: 103
- Это ошибка возникает в ситуации когда сервер ещё не успел запустить службу по скачиванию модов, а на самом сервере этого мода нет.
- Мод не найден:
{"message": "this mod was not found", "error_id": 2}}
HTTP code: 404
- Сервер уже пытается скачать этот мод:
{"message": "your request is already being processed", "error_id": 3}
HTTP code: 102
- Постоянно спрашивать состояние мода через эту функцию не рекомендую, так как она достаточно медленная.
Лучше использовать
/info/mod/{mod_id}
.
Нужно передать ID
мода.
Если у сервера уже есть этот мод - он его отправит как ZIP
архив со сжатием ZIP_BZIP2
.
Эта самая быстрая команда загрузки, но если на сервере не будет запрашиваемого мода никаких действий по его загрузке предпринято не будет.
JSON ответы:
- Мода нет на сервере:
{"message": "the mod is not on the server", "error_id": 1}
HTTP code: 404
2. Мод поврежден:
{"message": "the mod is damaged", "error_id": 2}
HTTP code: 404
- Если по какой-то причине мод есть в БД, но его файла нет в системе, запись в БД будет удалена, а вам сообщено что мод был поврежден и отправлен не будет.
Возвращает список модов к конкретной игре, которые есть на сервере. Имеет необязательные аргументы:
page_size
(int) - количество элементов которое будет возвращено. (диапазон значений1...50
)page
(int) - "страница" которая будет возвращена. Рассчитывается какpage_size * page = offeset
.sort
(str) - режим сортировки таблицы перед фильтрацией. Префиксi
указывает что сортировка должна быть инвертированной. По умолчанию от меньшего к большему, сi
от большего к меньшему.- NAME - сортировка по имени.
- SIZE - сортировка по размеру.
- DATE_CREATION - сортировка по дате создания.
- DATE_UPDATE - сортировка по дате обновления.
- DATE_REQUEST - сортировка по дате последнего запроса.
- SOURCE - сортировка по источнику.
- DOWNLOADS (по умолчанию) - сортировка по количеству загрузок.
tags
(list[int]) - список ID тегов которые должны иметь отправленные в ответе игры.games
(list[int]) - ID игр с которыми связан мод. По факту 1 мод связан максимум с 1 игрой, но архитектурой сервера это никак не ограничивается.dependencies
(bool) - отправлять ли моды имеющие зависимость на другие моды. По умолчаниюFalse
.primary_sources
(list[str]) - фильтрация по первоисточникам. Например:steam
,local
и т.п..name
(str) - фильтрация по имени. Необязательно писать полное имя.
JSON ответ:
{"message": "incorrect page size", "error_id": 1}
HTTP code: 413
- Означает что размер страницы не входит в диапазон
1...50
.
{"message": "the maximum complexity of filters is 30 elements in sum", "error_id": 2}
HTTP code: 413
- Максимальное суммарное размер фильтров
tags
,games
,primary_sources
не должно превышать 30 элементов.
{"database_size": int, "offeset": int, "results": list[dict]}
HTTP code: 200
database_size
- общий размер базы данных с текущими фильтрами (game_id
иsource
).offeset
- итоговый рассчитанный сдвиг с0
элемента в БД.results
- возвращает массив массивов в котором содержатся все элементы соответствующие текущему запросу (пустой список если ничего не найдено). Содержание под массива:-
-
id
(int) - id мода.
-
-
-
size
(int) - размер мода в байтах.
-
-
-
date_creation
(YYYY-MM-DD HH:MI:SS
) - дата появления в первоисточнике.
-
-
-
date_update
(YYYY-MM-DD HH:MI:SS
) - дата обновления в первоисточнике.
-
-
-
date_request
(YYYY-MM-DD HH:MI:SS.MS
) - дата последнего запроса.
-
-
-
source
(str) - первоисточник.
-
-
-
name
(str) - название мода.
-
-
-
description
(str) - описание мода.
-
-
-
condition
(int) - состояние мода (0
- загружен,1
- можно запрашивать, не до конца провалидирован,2
- скачивается).
-
-
-
downloads
(int) - количество загрузок данного мода.
-
Возвращает список игр, моды к которым есть на сервере. Имеет необязательные аргументы:
page_size
(int) - количество элементов которое будет возвращено.page
(int) - "страница" которая будет возвращена. Рассчитывается какpage_size * page = offeset
.sort
(str) - режим сортировки таблицы перед фильтрацией. Префиксi
указывает что сортировка должна быть инвертированной.NAME
- сортировка по имени.TYPE
- сортировка по типу (game
илиapp
).CREATION_DATE
- сортировка по дате регистрации на сервере.MODS_DOWNLOADS
- сортировка по суммарному количеству скачанных модов для игры (по умолчанию).MODS_COUNT
- сортировка по суммарному количеству модов для игры.SOURCE
- сортировка по источнику.
type_app
(list[str]) - фильтрация по типу (game
илиapp
).genres
(list[int]) - фильтрация по жанрам игр.primary_sources
(list[str]) - фильтрация по первоисточникам. Например:steam
,local
и т.п..name
(str) - фильтрация по имени. Необязательно писать полное имя.
JSON ответ:
- Некоректный размер страницы:
{"message": "incorrect page size", "error_id": 1}
HTTP code: 413
- Означает что размер страницы не входит в диапазон
1...50
.
- Слишком сложный запрос:
{"message": "the maximum complexity of filters is 30 elements in sum", "error_id": 2}
HTTP code: 413
- Максимальное суммарное размер фильтров
type_app
,genres
,primary_sources
не должно превышать 30 элементов.
- Нормальный ответ:
{"database_size": int, "offeset": int, "results": list[list]}
HTTP code: 404
database_size
- общий размер базы данных с текущими фильтрами.offeset
- итоговый рассчитанный сдвиг с0
элемента в БД.results
- возвращает массив массивов в котором содержатся все элементы соответствующие текущему запросу (пустой список если ничего не найдено). Содержание под массива:-
-
id
(int) - id игры.
-
-
-
name
(str) - название игры.
-
-
-
type
(str) - тип приложения (game
илиapp
).
-
-
-
logo
(str) -url
ведущий на лого игры.
-
-
-
short_description
(str) - короткое описание игры.
-
-
-
description
(str) - описание игры.
-
-
-
mods_downloads
(int) - суммарное количество загрузок у связанных с игрой модов.
-
-
-
mods_count
(int) - количество связанных модов.
-
-
-
creation_date
(YYYY-MM-DD HH:MI:SS.MS
) - дата регистрации на сервере
-
-
-
source
(str) - первоисточник.
-
Возвращает список тегов закрепленных за игрой и её модами. Нужно передать ID интересующей игры. Имеет необязательные аргументы:
page_size
(int) - размер 1 страницы. Диапазон - 1...50 элементов.page
(int) - номер странице. Не должна быть отрицательной.
JSON ответы:
- Некоректный размер страницы:
{"message": "incorrect page size", "error_id": 1}
HTTP code: 413
2. Нормальный ответ:
{"database_size": genres_count, "offset": offset, "results": genres}
HTTP code: 200
- Структура подсловаря в
results
: -
id
(int
) - ID элемента.
-
name
(str
) - название тега.
Возвращает список жанров для игр. Имеет необязательные аргументы:
page_size
(int) - размер 1 страницы. Диапазон - 1...50 элементов.page
(int) - номер странице. Не должна быть отрицательной.
JSON ответы:
- Некоректный размер страницы:
{"message": "incorrect page size", "error_id": 1}
HTTP code: 413
2. Нормальный ответ:
{"database_size": genres_count, "offset": offset, "results": genres}
HTTP code: 200
- Структура подсловаря в
results
: -
id
(int
) - ID элемента.
-
name
(str
) - название жанра.
Возвращает список ресурсов у конкретного мода. Нужно передать ID интересующего мода. Имеет необязательные аргументы:
page_size
(int) - размер 1 страницы. Диапазон - 1...50 элементов.page
(int) - номер странице. Не должна быть отрицательной.types_resources
(list[str]) - фильтрация по типам ресурсов. (logo
/screenshot
), ограничение - 20 элементов.
JSON ответы:
- Некоректный размер страницы:
{"message": "incorrect page size", "error_id": 1}
HTTP code: 413
- Означает что размер страницы не входит в диапазон
1...50
.
- Слишком сложный запрос:
{"message": "the maximum complexity of filters is 30 elements in sum", "error_id": 2}
HTTP code: 413
- Максимальный размер фильтра
types_resources
не должен превышать 30 элементов.
- Нормальный ответ:
{"database_size": int, "offset": int, "results": list[dict]}
HTTP code: 200
- Структура подсловаря в
results
: -
date_event
(YYYY-MM-DD HH:MI:SS.MS
) - дата последнего изменения записи на сервере.
-
id
(int
) - ID ресурса.
-
url
(str
) - ссылка на ресурс.
-
type
(str
) - тип ресурса (logo
/screenshot
).
-
owner_id
(int
) - ID мода-владельца.
Возвращает информацию об конкретном моде, а так же его состояние на сервере.
Нужно передать ID
мода. Имеет так же необязательный bool
аргумент dependencies
(по умолчанию false
).
JSON ответ:
{"result": dict / null}
HTTP code: 200
results
- возвращает либоnull
, либо словарь с результатом поиска. Структура словаря:-
-
id
(int) - id мода.
-
-
-
size
(int) - размер мода в байтах.
-
-
-
date_creation
(YYYY-MM-DD HH:MI:SS
) - дата появления в первоисточнике.
-
-
-
date_update
(YYYY-MM-DD HH:MI:SS
) - дата обновления в первоисточнике.
-
-
-
date_request
(YYYY-MM-DD HH:MI:SS.MS
) - дата последнего запроса.
-
-
-
source
(str) - первоисточник.
-
-
-
name
(str) - название мода.
-
-
-
description
(str) - описание мода.
-
-
-
condition
(int) - состояние мода (0
- загружен,1
- можно запрашивать, не до конца провалидирован,2
- скачивается).
-
-
-
downloads
(int) - количество загрузок данного мода.
-
- При
dependencies=true
возвращает дополнительные пункты:dependencies
(list[int]) - ограничено 20 элементами.dependencies_count
(int) - возвращает общее число элементов.
Возвращает информацию о конкретной игре.
Нужно передать только ID
игры.
JSON ответ:
{"result": list / null}
HTTP code: 200
results
- возвращает словарь в котором содержится информация об игре. Если игра не найдена, возвращаетnull
. Содержание словаря:-
-
id
(int) - id игры.
-
-
-
name
(str) - название игры.
-
-
-
type
(str) - тип приложения (game
илиapp
).
-
-
-
logo
(str) -url
ведущий на лого игры.
-
-
-
short_description
(str) - короткое описание игры.
-
-
-
description
(str) - описание игры.
-
-
-
mods_downloads
(int) - суммарное количество загрузок у связанных с игрой модов.
-
-
-
mods_count
(int) - количество связанных модов.
-
-
-
creation_date
(YYYY-MM-DD HH:MI:SS.MS
) - дата регистрации на сервере
-
-
-
source
(str) - первоисточник.
-
Возвращает информацию о состоянии мода/модов на сервере. Нужно передать массив с интересующими ID модов. Диапазон - 1...50 элементов
JSON ответ:
{"message": "the size of the array is not correct", "error_id": 1}
HTTP code: 413
- Означает что массив вышел за диапазон в 1...50 элементов.
{id: 0/1/2, ...}
HTTP code: 200
- В ответе возвращает только те элементы которые были переданы в запросе И есть на сервере.
- Об состояниях: (
0
- загружен,1
- можно запрашивать, не до конца провалидирован,2
- скачивается). - Если мода нет в ответе - значит его нет на сервере.
Возвращает информацию о скорости обработки запросов (измеряется в миллисекундах). В расчеты попадают 20 последних запросов.
JSON ответ:
{"fast": int, "full": int}
HTTP code: 200
-
fast
- скорость ответа сервера на запрос о моде который есть на сервере. -
full
- скорость ответа сервера на запрос о моде которого нет на сервере. Замер идет от момента получения запроса до момента переключение мода на состояние1
(можно запрашивать, не до конца провалидирован). -
Если сервер прислал (в одном из двух параметров)
0
- недостаточно данных для статистики по этому пункту.
Возвращает подробную статистику о запросах и работе сервера в конкретный день. Имеет необязательные аргументы:
day
(YYYY-MM-DD
;str
) - день по которому нужна статистика. По умолчанию - сегодня.start_hour
(int
) - фильтрация по минимальному значению часа (диапазон 0...23).end_hour
(int
) - фильтрация по максимальному значению часа (диапазон 0...23).
При фильтрации по часу отсекаются крайние значения, но не указанное.
Т.е. - если указать в start_hour
и в end_hour
одно и тоже значение,
то на выходе получите статистику только по этому часу.
JSON ответ:
- Выход начального времени из 24-часового диапазона:
{"message": "start_hour exits 24 hour format", "error_id": 1}
HTTP code: 412
2. Выход конечного времени из 24-часового диапазона:
{"message": "end_hour exits 24 hour format", "error_id": 2}
HTTP code: 412
3. Противоречивый запрос:
{"message": "conflicting request", "error_id": 3}
HTTP code: 409
- Возникает когда начальное время > конечного времени.
- Нормальный ответ:
list[dict]
HTTP code: 200
- Содержание словаря:
-
count
(int
) - количество чего-то в этот период времени.
-
type
(str
) - тип поля.
-
date_time
(YYYY-MM-DD HH:MI:SS.MS
- где все что меньше часа всегда равно0
) - дата и час.
Возвращает подробную статистику о запросах и работе сервера в конкретный день.
Принимает необязательные параметры:
start_date
(YYYY-MM-DD
;str
) - день от начала которого нужна статистика (включительно). По умолчанию =end_date
-7 days
.end_date
(YYYY-MM-DD
;str
) - день до которого нужна статистика (включительно). По умолчанию - текущая дата.
При фильтрации по дня отсекаются крайние значения, но не указанные.
Т.е. - если указать в start_date
и в end_date
одно и тоже значение,
то на выходе получите статистику только по этому дню.
JSON ответ:
- Противоречивый запрос:
{"message": "conflicting request", "error_id": 3}
HTTP code: 409
- Возникает когда начальная дата > конечной даты.
- Нормальный ответ:
list[dict]
HTTP code: 200
- Содержание словаря:
-
count
(int
) - количество чего-то в этот период времени.
-
type
(str
) - тип поля.
-
date
(YYYY-MM-DD
) - дата.
Возвращает общую информацию о состоянии базы данных. Не принимает аргументов.
JSON ответ:
{"mods": int, "games": int, "genres": int, "mods_tags": int, "mods_dependencies": int, "statistics_days": int}
HTTP code: 200
mods
(int
) - суммарное по всем играм количество модов на сервере.games
(int
) - количество проиндексированных.genres
(int
) - количество проиндексированных жанров игр.mods_tags
(int
) - суммарное по всем играм количество тегов для модов.mods_dependencies
(int
) - количество модов у которых есть зависимости на другие моды.statistics_days
(int
) - сколько уже дней ведётся статистика.mods_sent_count
(int
) - сколько раз сервер отправил пользователям файлы с модами.
Возвращает карту переводов для типов в статистической ветке. Не принимает аргументов.
Определяет на каком языке отправить ответ через поле Accept-Language
в headers
запроса.
JSON ответ:
{"language": select_language, "result": stc.cache_types_data(select_language)}
HTTP code: 200
language
(str
) - выбранный сервером язык. Пытается найти самый перевод для языков (по пользовательскому приоритету). Если не удалось найти язык по пользовательскому приоритету - устанавливаетсяru
как значение по умолчанию.result
(dict[str] = str
) - возвращает словарь с переводами для типов которые получаются в/statistics/day
и/statistics/hour
.
Если вы хотите по какой-то причине поднять сервер у себя, вот небольшая заметки :)
- Убедитесь что вы установили все зависимости из requirements.txt и у вас не возникли ошибки!
- Для корректного запуска сервера на Linux вам нужно выполнить этот пункт
- Если у вас возникли какие-то проблемы с установкой - пишите мне!
sudo adduser steam; sudo apt update; sudo apt upgrade; sudo apt-get install lib32stdc++6 -y; sudo apt install git -y; sudo apt install python3.10 -y; sudo apt -y install python3-pip; sudo apt install htop -y; sudo apt install screen -y; cd /home/steam; git clone https://github.com/Miskler/pytorrent.git; cd pytorrent; chmod -R 777 .; pip3 install -r requirements.txt; sudo snap install --classic certbot; sudo certbot certonly --standalone
Это займет некоторое время :) После перейти к шагу 7!
- Создание пользователя:
sudo adduser steam
- Обновление всех пакетов:
sudo apt update; sudo apt upgrade
- Установка по: (после рекомендую перезапустить ОС)
sudo apt-get install lib32stdc++6 -y; sudo apt install git -y; sudo apt install python3.10 -y; sudo apt -y install python3-pip; sudo apt install htop -y; sudo apt install screen -y
- Установка репозитория:
cd /home/steam; git clone https://github.com/Miskler/pytorrent.git; cd pytorrent; chmod -R 777 .
- Установка зависимостей:
pip3 install -r requirements.txt
- Установка CertBot (SSL сертификат):
sudo snap install --classic certbot; sudo ln -s /snap/bin/certbot /usr/bin/certbot; sudo certbot certonly --standalone
- Создание файла с настройками для сервера:
Создайте файл в каталоге
backend
со следующим содержимым:
bind = "0.0.0.0:443" # Указывает Gunicorn слушать все IP-адреса на порту 443
#По идее должен содержать значение:
certfile = "/etc/letsencrypt/live/YOU_DOMEN.com/fullchain.pem" # Путь к вашему HTTPS сертификату (фактический путь см в логах certbot)
#По идее должен содержать значение:
keyfile = "/etc/letsencrypt/live/YOU_DOMEN.com/privkey.pem" # Путь к вашему приватному ключу (фактический путь см в логах certbot)
workers = 1 # Количество рабочих процессов Gunicorn
- Запуск (должны находится в каталоге
backend
):
screen -S pytorrent_backend ./start.sh
Жмем сочитание клавиш CTRL + A + D
После проверяем адрес - https://YOU_DOMEN.com:8000/docs
. Если все ок вы увидете документацию.
9. Запуск телеграм бота:
Сначало получаем ключ бота. После создаем файл key.json
в папке telegram_bot
и записываем в него:
{"key": "YOU KEY"}
После выполняем команду:
screen -S telegram_bot python3 main.py