-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 2401ce8
Showing
15 changed files
with
671 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
.env | ||
**\__pycache__ | ||
*.json | ||
**.jpg | ||
Dockerfile | ||
venv | ||
dev*.txt | ||
ressources | ||
.gitignore |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
.env | ||
venv | ||
**/__pycache__ | ||
*.json | ||
dev*.txt |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
FROM python:3.12.5-alpine3.20 | ||
|
||
COPY requirements.txt /app/ | ||
|
||
WORKDIR /app | ||
|
||
RUN apk update && \ | ||
apk add gcc musl-dev linux-headers libc-dev libffi-dev openssl-dev make && \ | ||
pip install --default-timeout=100 --upgrade pip && \ | ||
pip install --default-timeout=100 -r requirements.txt | ||
|
||
ENV LANG=fr_FR.UTF-8 | ||
ENV LC_ALL=fr_FR.UTF-8 | ||
|
||
COPY . /app/ | ||
|
||
CMD ["python", "-u", "main.py"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
<h1 align='center'>Lansbot</h1> | ||
<p align="center"> | ||
<img src="https://github.com/LeGeRyChEeSe/LanPlay-DiscordBot/blob/main/lansbot.jpg?raw=true" align="center" height=205 alt="Lansbot" /> | ||
</p> | ||
<p align="center"> | ||
<img src='https://visitor-badge.laobi.icu/badge?page_id=LeGeRyChEeSe.Lansbot', alt='Visitors'/> | ||
<a href="https://github.com/LeGeRyChEeSe/LanPlay-DiscordBot/stargazers"> | ||
<img src="https://img.shields.io/github/stars/LeGeRyChEeSe/LanPlay-DiscordBot" alt="Stars"/> | ||
</a> | ||
<a href="https://github.com/LeGeRyChEeSe/LanPlay-DiscordBot/issues"> | ||
<img src="https://img.shields.io/github/issues/LeGeRyChEeSe/LanPlay-DiscordBot" alt="Issues"/> | ||
</a> | ||
|
||
<p align="center"> | ||
A Discord bot that provides information on <a href="http://lan-play.com">LAN Play</a> servers, players, and games played. | ||
<p align="center"> | ||
|
||
# Table of Contents | ||
- [Get API Key](#get-api-key) | ||
- [Create a Bot Account](#create-a-bot-account) | ||
- [Invite the bot into your server](#invite-the-bot-into-your-server) | ||
- [Run the Bot](#run-the-bot) | ||
- [Commands Available](#commands-available) | ||
- [Contributing](#contributing) | ||
- [License](#license) | ||
- [Acknowledgements](#acknowledgements) | ||
- [Star History](#star-history) | ||
|
||
|
||
## Get API Key | ||
|
||
To use the LanPlay package you will need a specific, non-transferable API key that can be retrieved from <a href="http://www.lan-play.com">LanPlay</a>.<br> | ||
|
||
Please follow these steps : | ||
|
||
1. Open a Web Browser and go to http://www.lan-play.com | ||
|
||
2. Open a Console Mode (<b>Ctrl + Shift + C</b> or <b>F12</b> should work, or Google is your friend to find how to access the Console Mode 🫠) | ||
|
||
3. Go to `Network` tab and refresh the current page | ||
|
||
4. Search a line named `getMonitors` and click on it | ||
|
||
5. Open the `Payload` tab | ||
|
||
6. Copy the `api_key` value and store it in safe location for the [Run the Bot](#run-the-bot) step. | ||
|
||
## Create a Bot Account | ||
|
||
1. Make sure you’re logged on to the [Discord website](https://discord.com/). | ||
|
||
2. Navigate to the [Discord Application](https://discord.com/developers/applications) for developers. | ||
|
||
3. Click on the `New Application` button. | ||
|
||
4. Give the application a name and click `Create`. | ||
|
||
5. Navigate to the `Bot` tab to configure it. | ||
|
||
6. Make sure that `Public Bot` is ticked if you want others to invite your bot. | ||
|
||
- You should also make sure that `Require OAuth2 Code Grant` is unchecked. | ||
|
||
7. Copy the token using the `Copy` button and store it in safe location for the [Run the Bot](#run-the-bot) step. | ||
|
||
- <b>This is not the Client Secret at the General Information page.</b> | ||
|
||
> It should be worth noting that this token is essentially your bot’s password. You should never share this with someone else. In doing so, someone can log in to your bot and do malicious things, such as leaving servers, ban all members inside a server, or pinging everyone maliciously. | ||
> | ||
> The possibilities are endless, so do not share this token. | ||
> | ||
> If you accidentally leaked your token, click the `Regenerate` button as soon as possible. This revokes your old token and re-generates a new one. Now you need to use the new token to login. | ||
|
||
## Invite the bot into your server | ||
|
||
1. Navigate to the [Discord Application](https://discord.com/developers/applications) for developers. | ||
|
||
2. Open the App you previously created for the Bot. | ||
|
||
3. Navigate to `OAuth2` tab. | ||
|
||
4. Scroll down and in `OAuth2 URL Generator` -> `SCOPES`, tick these boxes: | ||
|
||
- `bot` | ||
- `applications.commands` | ||
|
||
5. Scroll down and in `BOT PERMISSIONS`, tick these boxes: | ||
|
||
- `Manage Expressions` | ||
- `Create Expressions` | ||
- `Send Messages` | ||
- `Send Messages in Threads` | ||
- `Embed Links` | ||
- `Read Message History` | ||
|
||
6. Make sure that `INTEGRATION TYPE` value is `Guild Install`. | ||
|
||
7. Copy/Paste the `GENERATED URL` at bottom to a new Browser Tab and add it to your Discord Server. | ||
|
||
## Run the Bot | ||
|
||
- Download [Docker](https://www.docker.com) and install it on your computer. | ||
|
||
- Make sure you got both [api_key](#get-api-key) and [token](#create-a-bot-account) values, and [invited the bot to your server](#invite-the-bot-into-your-server). | ||
|
||
- Open a <b>Windows Terminal</b> and execute the following command to run the Discord Bot: | ||
|
||
```docker | ||
docker run -e API_LAN_KEY=<your_lan_api_key> -e TOKEN=<your_discord_token> LeGeRyChEeSe/lanplay-discordbot:latest | ||
``` | ||
|
||
- If you want the Discord Bot running in background: | ||
|
||
```docker | ||
docker run -d -e API_LAN_KEY=<your_lan_api_key> -e TOKEN=<your_discord_token> LeGeRyChEeSe/lanplay-discordbot:latest | ||
``` | ||
|
||
> Replace `<your_lan_api_key>` with your [`api_key`](#get-api-key) and replace `<your_discord_token>` with your [`token`](#create-a-bot-account). | ||
## Commands Available | ||
|
||
| Command | Input | Output | Permission | | ||
| :-----: | :--------: | :----: | :--------: | | ||
| `/help` | `None` | ![Help Menu](https://github.com/LeGeRyChEeSe/LanPlay-DiscordBot/blob/main/ressources/help.png?raw=true) | `Everybody` | | ||
| `/lan` | <i>select a server</i> | ![LanPlay Server Infos](https://github.com/LeGeRyChEeSe/LanPlay-DiscordBot/blob/main/ressources/lan.png?raw=true) | `Everybody` | | ||
| `/add` | `server`<br><i>e.g. 'tekn0.net:11451'</i> | ![Status of server addition](https://github.com/LeGeRyChEeSe/LanPlay-DiscordBot/blob/main/ressources/add.png?raw=true) | `Admin` | | ||
| `/delete` | `server`<br><i>e.g. 'tekn0.net:11451'</i> | ![Status of server deletion](https://github.com/LeGeRyChEeSe/LanPlay-DiscordBot/blob/main/ressources/delete.png?raw=true) | `Admin` | | ||
|
||
## Contributing | ||
|
||
Any contributions you make are **greatly appreciated**. | ||
|
||
1. Fork the Project | ||
2. Create your Feature Branch (`git checkout -b feature/NewFeature`) | ||
3. Commit your Changes (`git commit -m 'Add some NewFeature'`) | ||
4. Push to the Branch (`git push origin feature/NewFeature`) | ||
5. Open a Pull Request | ||
|
||
|
||
<i>Thanks to every [contributors](https://github.com/LeGeRyChEeSe/LanPlay-DiscordBot/graphs/contributors) who have contributed in this project.</i> | ||
|
||
## License | ||
|
||
Distributed under the MIT License. See [LICENSE](https://github.com/LeGeRyChEeSe/LanPlay-DiscordBot/blob/main/LICENSE) for more information. | ||
|
||
## Acknowledgements | ||
|
||
Shoutout to <b>LizardByte</b> for the Sunshine repo: https://github.com/LizardByte/Sunshine | ||
|
||
Shoutout to <b>itsmikethetech</b> for the Virtual Display Driver repo: https://github.com/itsmikethetech/Virtual-Display-Driver | ||
|
||
Thanks to <b>Cynary</b> for the Sunshine Virtual Monitor scripts: https://github.com/Cynary/sunshine-virtual-monitor | ||
|
||
Shoutout to <b>JosefNemec</b> for Playnite: https://github.com/JosefNemec/Playnite | ||
|
||
Shoutout to <b>Nonary</b> for the PlayNiteWatcher script: https://github.com/Nonary/PlayNiteWatcher | ||
|
||
## Star History | ||
|
||
[![Star History Chart](https://api.star-history.com/svg?repos=LeGeRyChEeSe/LanPlay-DiscordBot&type=Date)](https://star-history.com/#LeGeRyChEeSe/LanPlay-DiscordBot&Date) | ||
|
||
---- | ||
|
||
Author/Maintainer: [Garoh](https://github.com/LeGeRyChEeSe/) | Discord: garohrl |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,170 @@ | ||
import requests | ||
import disnake | ||
import json | ||
import os | ||
import typing | ||
from datetime import datetime | ||
from decouple import config | ||
from disnake.ext import commands | ||
from gql import gql, Client | ||
from gql.transport.aiohttp import AIOHTTPTransport | ||
|
||
list_all_games_url = "https://tinfoil.media/Title/ApiJson/" | ||
monitors_url = "https://api.uptimerobot.com/v2/getMonitors" | ||
API_LAN_KEY = config('API_LAN_KEY') | ||
lan_menu_url = "http://lan-play.com" | ||
lan_config_url = "http://lan-play.com/install-switch" | ||
image_lanplay_url = "http://lan-play.com/img/logo.f64272e3.png" | ||
|
||
|
||
async def getLanPlayInfos(lan_server_url: str) -> typing.Optional[typing.Dict]: | ||
transport = AIOHTTPTransport(url=lan_server_url) | ||
async with Client( | ||
transport=transport, | ||
) as session: | ||
|
||
query = gql(""" | ||
query getUsers { | ||
room { | ||
contentId | ||
hostPlayerName | ||
nodeCountMax | ||
nodeCount | ||
advertiseData | ||
nodes { | ||
playerName | ||
} | ||
} | ||
serverInfo { | ||
online | ||
idle | ||
} | ||
} | ||
""") | ||
|
||
try: | ||
result = await session.execute(query) | ||
except: | ||
return | ||
else: | ||
if hasRooms(result): | ||
list_games = matchGame(result["room"]) | ||
if list_games and len(list_games) > 0: | ||
for room in result["room"]: | ||
for game in list_games: | ||
if room["contentId"].lower() == game["id"].lower(): | ||
gameName = game["name"][game["name"].find( | ||
'\"\u003e') + 2: game["name"].find('\u003c/a\u003e')] | ||
iconUrl = game["icon"][game["icon"].find( | ||
'url') + 4: game["icon"].find(')\"')] | ||
room["gameName"] = gameName | ||
room["iconUrl"] = iconUrl | ||
return result | ||
|
||
|
||
async def getNumberOfRooms(lan_server_url: str) -> int: | ||
transport = AIOHTTPTransport(url=lan_server_url) | ||
async with Client( | ||
transport=transport, | ||
) as session: | ||
|
||
query = gql(""" | ||
query getUsers { | ||
room { | ||
nodeCount | ||
} | ||
} | ||
""") | ||
|
||
result = await session.execute(query) | ||
return len(result["room"]) | ||
|
||
|
||
def hasRooms(server: typing.Dict) -> bool: | ||
return isinstance(server.get("room", []), list) and bool(server["room"]) | ||
|
||
|
||
def matchGame(rooms: list) -> list: | ||
list_all_games = requests.get(list_all_games_url) | ||
if not list_all_games.ok: | ||
return [] | ||
|
||
list_all_games = list_all_games.json() | ||
content_ids = set([room["contentId"].lower() for room in rooms]) | ||
list_games = [game for game in list_all_games["data"] | ||
if game["id"].lower() in content_ids] | ||
|
||
for game in list_games: | ||
if game["id"].lower() == "ffffffffffffffff": | ||
game["id"] = "0100B04011742000" | ||
|
||
return list_games | ||
|
||
|
||
def getLanServers() -> typing.Dict: | ||
response = requests.post(monitors_url, json={ | ||
"api_key": API_LAN_KEY, "format": "json", "all_time_uptime_ratio": 1}) | ||
return response.json() | ||
|
||
|
||
def getLocalization(bot: commands.InteractionBot, key: str, locale: disnake.Locale, **kwargs) -> typing.Optional[str]: | ||
text_localized = bot.i18n.get(key).get(str(locale)) | ||
|
||
for k, value in kwargs.items(): | ||
k_formatted = "{" + k + "}" | ||
text_localized = text_localized.replace(k_formatted, str(value)) | ||
|
||
return text_localized if text_localized else None | ||
|
||
|
||
def load_lan_servers(filename: str = 'lan_servers.json') -> typing.Optional[typing.Union[typing.List[typing.Dict[str, typing.Union[str, int]]], list]]: | ||
if os.path.exists(filename): | ||
with open(filename, 'r') as file: | ||
return json.load(file) | ||
return [] | ||
|
||
|
||
def save_lan_servers(lan_servers: typing.List[typing.Dict[str, typing.Union[str, int]]], filename: str = 'lan_servers.json') -> None: | ||
with open(filename, 'w') as file: | ||
json.dump(lan_servers, file, indent=4) | ||
|
||
|
||
def create_custom_server(friendly_name: str) -> typing.Dict[str, typing.Union[str, int]]: | ||
return { | ||
"id": friendly_name.split(':')[0], # Utiliser la partie avant les ':' | ||
"friendly_name": friendly_name, | ||
"url": f"http://{friendly_name}/info", | ||
"type": 1, | ||
"sub_type": "", | ||
"keyword_type": "None", | ||
"keyword_case_type": 0, | ||
"keyword_value": "", | ||
"http_username": "", | ||
"http_password": "", | ||
"port": "", | ||
"interval": 300, | ||
"timeout": 30, | ||
"status": 9, | ||
"create_datetime": int(datetime.now().timestamp()), # Timestamp actuel | ||
"all_time_uptime_ratio": "99.999" | ||
} | ||
|
||
|
||
def add_custom_server(temp_lan_servers: typing.List[typing.Dict[str, typing.Union[str, int]]], friendly_name, lan_servers=None) -> bool: | ||
custom_server = create_custom_server(friendly_name) | ||
|
||
for server in temp_lan_servers: | ||
if custom_server["id"] == server["id"]: | ||
return False | ||
|
||
if lan_servers: | ||
for server in lan_servers["monitors"]: | ||
if custom_server["friendly_name"] == server["friendly_name"]: | ||
return False | ||
|
||
temp_lan_servers.append(custom_server) | ||
return True | ||
|
||
|
||
def delete_custom_server(lan_servers: typing.List[typing.Dict[str, typing.Union[str, int]]], friendly_name: str) -> typing.List[typing.Dict[str, typing.Union[str, int]]]: | ||
return [server for server in lan_servers if server.get("friendly_name") != friendly_name] |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.