90 Commits

Author SHA1 Message Date
0822e309db Merge pull request 'Fixed footers' (#4) from wip into main
Reviewed-on: #4
2025-03-28 19:26:55 +01:00
85827eddc5 Fixed footers 2025-03-28 18:26:14 +00:00
a6a62e84d3 Merge pull request 'Nouveau footer - changement de nom des images' (#3) from wip into main
Reviewed-on: #3
2025-03-28 19:22:54 +01:00
06eef00c79 Nouveau footer - changement de nom des images 2025-03-28 18:20:37 +00:00
6d4a160416 New logo - dark 2025-03-28 16:10:40 +00:00
7894b03883 Fixed schematics definition 2025-03-28 15:26:25 +00:00
c787c61332 Merge branch 'wip' 2025-03-28 15:24:24 +00:00
d6b5273e5a Fixed list 2025-03-28 15:23:55 +00:00
10ab4f6fc0 Merge branch 'wip' 2025-03-28 15:21:02 +00:00
f133344f7a fixed schematics 2025-03-28 15:20:50 +00:00
d1609d0776 Contributeurs 2025-03-28 15:05:18 +00:00
bf5fa6203b Merge branch 'wip' 2025-03-28 14:37:12 +00:00
aae087c91b New pp 2025-03-28 14:36:48 +00:00
b69b45a03f Merge branch 'wip' 2025-03-28 13:36:33 +00:00
5503fbf275 fixed logo 2025-03-28 13:35:56 +00:00
2b192247bb Merge pull request 'Nouvelle pp + section capture' (#2) from wip into main
Reviewed-on: #2
2025-03-28 10:16:27 +01:00
e1e3502be2 Nouvelle pp + section capture 2025-03-28 09:12:55 +00:00
e585f18a93 Merge branch 'wip' 2025-03-27 22:18:18 +00:00
fc6ae91c55 Minor changes 2025-03-27 22:17:30 +00:00
a496a1b1bf Merge branch 'wip' 2025-03-27 22:09:03 +00:00
1722f276a9 Logo 2025-03-27 22:07:26 +00:00
38b60300c4 Logo 2025-03-27 22:05:59 +00:00
6a6336a07c Merge pull request 'wip - Fusion refonte README.md & LICENSE' (#1) from wip into main
Reviewed-on: #1
2025-03-27 21:01:19 +01:00
ef27e320e2 Refonte README + License 2025-03-27 19:57:30 +00:00
16e80db82f Merge branch 'wip' of https://git.djeex.fr/Djeex/nvidia-stock-bot into wip 2025-03-27 18:31:07 +00:00
3dd9dd5946 Minor changes 2025-03-27 18:30:07 +00:00
9dd3d76d7f Disclaimer IA 2025-03-27 18:29:49 +00:00
45b6bed116 Minor changes 2025-03-27 18:27:03 +00:00
24cad015bc Minor changes 2025-03-27 18:25:55 +00:00
b0309f34fe Disclaimer IA 2025-03-27 18:23:53 +00:00
841ffb5efe Minor changes 2025-03-27 10:59:14 +00:00
d4e34f20ec Minor changes 2025-03-27 10:39:43 +00:00
ddfbe853e9 fix png -> jpg 2025-03-27 10:19:06 +00:00
4115825953 illustration discord 2025-03-27 10:18:18 +00:00
dfa3a5e19c In english 2025-03-26 15:38:46 +00:00
cdbb1be864 Minor change 2025-03-26 12:01:31 +00:00
3ed38e7aa3 badge license 2025-03-26 12:01:12 +00:00
c392efce35 Ajout license 2025-03-26 11:55:09 +00:00
2761a9dacb License 2025-03-26 11:53:23 +00:00
006531aacc Maj intro 2025-03-14 15:12:40 +00:00
a8d4c05c81 Fix python section 2025-03-14 15:08:30 +00:00
280e8d0347 Maj schema 2025-03-14 15:05:06 +00:00
53c46b1d2f WIP to MAIN 2025-03-14 12:02:54 +00:00
5b1e180c6f Minor changes 2025-03-14 11:51:48 +00:00
7872f8aa00 Fixed sku notif 2025-03-14 11:33:50 +00:00
23b2f375fc Minor fixes 2025-03-14 11:21:56 +00:00
62bc725a1c Fixed coma 2025-03-14 11:04:57 +00:00
b381efd257 Readme 2025-03-14 10:55:41 +00:00
037f5bebf8 SKU changes & better notif 2025-03-14 10:53:59 +00:00
0803e3074b Meilleur masquage du webhook 2025-02-24 09:58:36 +00:00
21f6bd7a1f Better notification 2025-02-21 22:39:23 +00:00
8e2e91a760 pictures 2025-02-21 21:14:09 +00:00
d95afc4627 Commentaires 2025-02-21 16:08:10 +00:00
d97a32623f Illustration 2025-02-21 15:55:23 +00:00
705a96d0c2 Minor changes 2025-02-21 15:24:13 +00:00
66ca9e907d Merge branch 'main' of https://git.djeex.fr/Djeex/nvidia-stock-bot 2025-02-21 15:20:18 +00:00
82557b77ab Last commit 2025-02-21 15:13:09 +00:00
d48d9d537b auto sku 2025-02-19 17:25:23 +00:00
8d1fd5d94a auto sku 2025-02-19 17:23:48 +00:00
86665b7137 auto sku 2025-02-19 17:19:49 +00:00
f9bc3dfe32 new env 2025-02-19 12:25:03 +00:00
bd5b703eb7 new env variable 2025-02-19 11:11:58 +00:00
af88b778bf fixes script 2025-02-11 22:16:54 +00:00
57a64b0274 Update 2025-02-11 21:47:24 +00:00
95bb127cdf New script 2025-02-11 21:45:13 +00:00
8ccc925966 Readme 2025-02-11 21:04:49 +00:00
dcd666c39b Test 2025-02-11 20:57:20 +00:00
20aa4991a8 1st commit 2025-02-11 20:56:20 +00:00
6f01f67799 New product url + latest tag 2025-01-31 09:07:33 +00:00
952b203461 Fixed URL 2025-01-30 23:41:09 +00:00
5487e0f7f8 Fixed discord embed 2025-01-30 23:35:03 +00:00
f59890c7e5 Fixed msg link 2025-01-30 22:45:48 +00:00
43c08dedaf Fixed API url 2025-01-30 19:09:34 +00:00
9833409672 Fix stock issues 2025-01-30 16:18:59 +00:00
1618b8e4e2 Nvidia API Update 2025-01-30 08:18:53 +00:00
8ccd221199 New nvidia API 2025-01-29 18:54:08 +00:00
f45435d8e0 Fixed urls 2025-01-28 13:42:55 +00:00
2a2c5ebe83 Minor changes 2025-01-28 13:41:34 +00:00
22199b5af0 Minor changes 2025-01-28 13:38:47 +00:00
87af4307da Installations 2025-01-28 13:37:02 +00:00
ba9bed12c3 Discord msg 2025-01-27 15:52:33 +00:00
57d4f0679b Minor changes 2025-01-26 12:12:01 +00:00
dfc632bd4e Minor changes 2025-01-26 12:11:40 +00:00
1ed838d252 docker-compose 2025-01-26 12:10:42 +00:00
d935b7836f Minor changes 2025-01-26 11:43:11 +00:00
2ff26bef24 fix wrong img url 2025-01-26 11:42:43 +00:00
88c09ff4cf illustration 2025-01-26 11:41:47 +00:00
1dae30df0b fix image name 2025-01-17 11:07:01 +00:00
c9d4bd7e2c Merge branch 'main' of https://git.djeex.fr/Djeex/nvidia-stock-bot 2025-01-17 11:00:56 +00:00
3006825705 fix errors 2025-01-17 10:59:42 +00:00
11 changed files with 427 additions and 96 deletions

View File

@ -19,4 +19,4 @@ ENV DISCORD_WEBHOOK_URL="https://example.com/webhook" \
REFRESH_TIME="60"
# Exposer un point de commande pour exécuter le script
CMD ["python", "bot_nvidia.py"]
CMD ["python", "nvidia-stock-bot.py"]

24
LICENSE Normal file
View File

@ -0,0 +1,24 @@
Creative Commons Attribution-NonCommercial 4.0 International License (CC BY-NC 4.0)
Copyright (c) 2025 Djeex
This work is licensed under the Creative Commons Attribution-NonCommercial 4.0 International License.
You are free to:
Share — copy, distribute, and transmit the material in any medium or format
Adapt — remix, transform, and build upon the material
Under the following terms:
Attribution — You must give appropriate credit, provide a link to the license, and indicate if changes were made. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use.
NonCommercial — You may not use the material for commercial purposes.
No additional restrictions — You may not apply legal terms or technological measures that legally restrict others from doing anything the license permits.
You can review the full license here:
https://creativecommons.org/licenses/by-nc/4.0/
DISCLAIMER: This text does not constitute legal advice. For any legal questions, please consult a professional.

164
README.md
View File

@ -1,46 +1,166 @@
# Nvidia Stock Bot
Par KevOut & Djeex
<h1 align="center"> Nvidia Stock Bot</h1>
<div align="center">
<a href="https://discord.gg/gxffg3GA96">
<img src="https://img.shields.io/badge/JV%20hardware-rejoindre-green?style=flat-square&logo=discord&logoColor=%23fff" alt="JV Hardware">
<a href="https://creativecommons.org/licenses/by-nc/4.0/" target="_blank">
<img src="https://img.shields.io/badge/License-CC%20BY--NC%204.0-8E44AD?style=flat-square" alt="License: CC BY-NC 4.0">
</a>
[![](https://img.shields.io/badge/JV%20hardware-rejoindre-green?style=flat-square&logo=discord&logoColor=%23fff&label=JV%20hardware&link=https%3A%2F%2Fdiscord.gg%2Fgxffg3GA96)](https://discord.gg/gxffg3GA96)
</div>
<div align="center" >
<img src="https://git.djeex.fr/Djeex/nvidia-stock-bot/raw/branch/main/assets/img/nvidia-stock-bot-logo.png" alt="Nvidia Stock Bot" width="300">
</div>
**Nvidia Stock Bot** - Un robot qui permet d'être alerté en temps réel des stocks de cartes graphiques **Nvidia RTX FE** grâce à des notifications Discord.
Ce robot :
- Appelle régulièrement l'api des stocks français de nvidia FE (par défaut toutes les 60s)
- Vérifie si RTX 5090, RTX 5080, RTX 5070ti et RTX 5070 sont en stock
- Si du stock est trouvé, envoie une notification discord via le webhook paramétré
*Le code a été en partie rédigé et structuré à l'aide d'une IA générative.*
## Sommaire
- [Fonctionnalités](#fonctionnalit%C3%A9s)
- [Installation docker sans le dépot (rapide)](#installation-sans-le-d%C3%A9pot-avec-docker-compose)
- [Installation docker avec le dépot (développeur)](#installation-avec-le-d%C3%A9pot)
- [Installation avec Python (développeur)](#installation-avec-python)
- [Captures d'écran](#captures-d%C3%A9cran)
- [Contributeurs](#contributeurs)
## Fonctionnalités
- Notification Discord `@everyone` en cas de changement du SKU (potentiel drop imminent)
- Notification Discord `@everyone` en cas de stock détecté avec modèle, prix, et lien
- Notification Discord silencieuse en cas d'absence de stock détécté
- Choix de la fréquence de la vérification
- Choix du modèle à surveiller
<img src="https://git.djeex.fr/Djeex/nvidia-stock-bot/raw/branch/main/assets/img/nvbot_schematics.png" align="center">
## Installation sans le dépot avec docker compose
Vous trouverez-ci dessous les instructions pour configurer le conteneur avec notre image pré-compilée. Avec cette solution, votre bot tournera tout seul tant que le conteneur est actif.
**Pré-requis**
- [Docker](https://docs.docker.com/engine/install/)
**Configuration**
- Créez un dossier `nvidia-stock-bot`
- Créez le fichier `compose.yaml` dans ce dossier avec la configuration ci-dessous :
```yaml
version: "3.8"
services:
nvidia-stock-bot:
image: git.djeex.fr/djeex/nvidia-stock-bot:latest
container_name: nvidia-stock-bot
restart: always
environment:
- DISCORD_WEBHOOK_URL= # URL de votre webhook Discord
- REFRESH_TIME= # Durée de rafraichissement du script en secondes
- API_URL_SKU= # API listant le produit par exemple https://api.nvidia.partners/edge/product/search?page=1&limit=100&locale=fr-fr&Manufacturer=Nvidia&gpu=RTX%205090
- API_URL_STOCK= # API appelant le stock sans préciser la valeur du sku, par exemple https://api.store.nvidia.com/partner/v1/feinventory?locale=fr-fr&skus=
- PRODUCT_URL= # URL d'achat du GPU
- PRODUCT_NAME= # Le nom du GPU qui s'affiche dans les notifications
- TEST_MODE= # true pour tester les notifications discord. false par défaut.
- PYTHONUNBUFFERED=1 # Permet d'afficher les logs en temps réel
command: python nvidia-stock-bot.py # Lance le script Python au démarrage du conteneur
```
**Lancer l'image**
Rendez-vous dans le dossier `nvidia-stock-bot` et lancez le conteneur :
```sh
docker compose up -d
```
**Voir les logs pour vérifier le bon fonctionnement**
```sh
docker logs -f nvidia-stock-bot
```
## Installation avec le dépot
### Pré-requis
- Git
- Docker
Vous trouverez-ci dessous les instructions pour installer le dépot, compiler l'image docker, et lancer le conteneur. Avec cette solution, votre bot tournera tout seul tant que le conteneur est actif.
### Cloner et paramétrer
**Pré-requis**
- [Git](https://git-scm.com/docs)
- [Docker](https://docs.docker.com/engine/install/)
Clonez le repo :
**Cloner et paramétrer**
- Clonez le repo :
```sh
git clone https://git.djeex.fr/Djeex/nvidia-stock-bot.git
```
Rendez-vous dans le dossier `nvidia-stock-bot/docker` et éditez le fichier `.env` avec :
- l'url de votre webhook discord
- la fréquence de consultation des stock (par défaut 60s, attention à ne pas trop descendre sous peine de blocage de votre adresse IP par nVidia)
### Lancer l'image
- Rendez vous dans le dossier `nvidia-stock-bot` et compilez l'image docker :
```sh
docker build -t nvidia-stock-bot .
```
- Puis rendez-vous dans le dossier `nvidia-stock-bot/docker` et éditez le fichier `.env` avec :
- l'url de votre webhook discord
- les différents liens API et produits
- la fréquence de consultation des stock (par défaut 60s, attention à ne pas trop descendre sous peine de blocage de votre adresse IP par nVidia)
**Lancer l'image**
Rendez-vous dans le dossier `nvidia-stock-bot/docker` et lancez le conteneur :
```sh
docker compose up -d
```
### Voir les logs pour vérifier le bon fonctionnement
**Voir les logs pour vérifier le bon fonctionnement**
```sh
docker logs -f nvidia-stock-bot
```
## Si vous souhaitez compiler vous même
## Installation avec Python
Rendez vous dans le dossier `nvidia-stock-bot` et compilez l'image docker :
```sh
docker build -t nvidia-stock-bot .
```
Vous trouverez ci-dessous comment exécuter directement le script Python. Avec cette solution, le bot s'arretera si vous fermez votre terminal.
**Pré-requis**
- Python 3.11 ou plus
- requests : `pip install requests`
**Configuration**
- Créez un environnement virtuel (exemple : `python3 -m venv nom_de_l_environnement` )
- Créez un dossier et aller dedans
- Téléchargez le script python :
```sh
curl -o nvidia-stock-bot.py -# https://git.djeex.fr/Djeex/nvidia-stock-bot/raw/branch/main/nvidia-stock-bot.py
```
- Exportez les variables d'environnement avec votre webhook discord et le temps de rafraichissement en secondes, par exemple :
```sh
export DISCORD_WEBHOOK_URL="https://votre_url_discord"
export REFRESH_TIME="60"
export API_URL_SKU="https://api.nvidia.partners/edge/product/search?page=1&limit=100&locale=fr-fr&Manufacturer=Nvidia&gpu=RTX%205080"
export API_URL_STOCK="https://api.store.nvidia.com/partner/v1/feinventory?locale=fr-fr&skus="
export PRODUCT_URL= "https://marketplace.nvidia.com/fr-fr/consumer/graphics-cards/?locale=fr-fr&page=1&limit=12&gpu=RTX%205080&manufacturer=NVIDIA"
export PRODUCT_NAME="RTX 5080"
export TEST_MODE=false
```
- Lancez le script
```sh
python nvidia-stock-bot.py
```
## Captures d'écran
<div align="center" >
<img src="https://git.djeex.fr/Djeex/nvidia-stock-bot/raw/branch/main/assets/img/nvidia-stock-bot-discord.png" alt="Nvidia Stock Bot - captures">
</div>
## Contributeurs
On remercie pour leurs contributions :
- Djeex
- KevOut
- Extreme2pac

BIN
assets/img/RTX5000.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

BIN
assets/img/ds_wh_pp.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 499 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View File

@ -1,2 +1,6 @@
DS_HOOK="votre url du webhook discord"
FREQ=60 #frequence de rafraichissement en secondes
DS_HOOK= #votre url du webhook Discord
FREQ= #frequence de rafraichissement en secondes
API_URL_SKU= # API listant le produit par exemple https://api.nvidia.partners/edge/product/search?page=1&limit=100&locale=fr-fr&Manufacturer=Nvidia&gpu=RTX%205090
API_URL_STOCK= # API appelant le stock sans préciser la valeur du sku, par exemple https://api.store.nvidia.com/partner/v1/feinventory?locale=fr-fr&skus=
PRODUCT_URL= # URL d'achat du GPU
PRODUCT_NAME= #Le nom du GPU qui s'affiche dans les notifications

View File

@ -1,7 +1,7 @@
version: "3.8"
services:
nvidia-stock-bot:
image: git.djeex.fr/djeex/nvidia-stock-bot
image: nvidia-stock-bot
container_name: nvidia-stock-bot
restart: always # Le conteneur redémarrera automatiquement en cas d'échec
env_file:
@ -9,5 +9,7 @@ services:
environment:
- DISCORD_WEBHOOK_URL=${DS_HOOK}
- REFRESH_TIME=${FREQ}
- API_URL_SKU=${API_URL_SKU}
- API_URL_STOCK=${API_URL_STOCK}
- PYTHONUNBUFFERED=1 # Permet d'afficher les logs en temps réel
command: python bot_nvidia.py # Lance le script Python
command: python nvidia-stock-bot.py # Lance le script Python

View File

@ -2,42 +2,64 @@ import requests
import logging
import time
import os
import re
from requests.adapters import HTTPAdapter, Retry
# Configuration du logger
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s [%(levelname)s] %(message)s",
)
logging.info("Démarrage du script")
# Récupération des variables d'environnement
try:
DISCORD_WEBHOOK_URL = os.environ['DISCORD_WEBHOOK_URL']
API_URL_SKU = os.environ['API_URL_SKU']
API_URL_STOCK = os.environ['API_URL_STOCK']
REFRESH_TIME = int(os.environ['REFRESH_TIME']) # Convertir en entier
TEST_MODE = os.environ.get('TEST_MODE', 'False').lower() == 'true'
PRODUCT_URL = os.environ['PRODUCT_URL']
PRODUCT_NAME = os.environ['PRODUCT_NAME']
# Regex pour extraire l'ID et le token
match = re.search(r'/(\d+)/(.*)', DISCORD_WEBHOOK_URL)
if match:
webhook_id = match.group(1)
webhook_token = match.group(2)
# Masquer derniers caractères de l'ID
masked_webhook_id = webhook_id[:len(webhook_id) - 10] + '*' * 10
# Masquer derniers caractères du token
masked_webhook_token = webhook_token[:len(webhook_token) - 120] + '*' * 10
# Reconstruction de l'url masquée
wh_masked_url = f"https://discord.com/api/webhooks/{masked_webhook_id}/{masked_webhook_token}"
except KeyError as e:
logging.error(f"Variable d'environnement manquante : {e}")
exit(1) # Quitter le script proprement en cas d'erreur
exit(1)
except ValueError:
logging.error("REFRESH_TIME doit être un entier valide.")
exit(1)
# Afficher les valeurs des variables d'environnement
print(f"url du webhook Discord: {DISCORD_WEBHOOK_URL}")
print(f"Temps d'actualisation (en secondes) : {REFRESH_TIME}")
# Affichage des URLs et configurations
logging.info(f"GPU: {PRODUCT_NAME}")
logging.info(f"URL Webhook Discord: {wh_masked_url}")
logging.info(f"URL API SKU: {API_URL_SKU}")
logging.info(f"URL API Stock: {API_URL_STOCK}")
logging.info(f"URL produit: {PRODUCT_URL}")
logging.info(f"Temps d'actualisation: {REFRESH_TIME} secondes")
logging.info(f"Mode Test: {TEST_MODE}")
# LURL de lAPI (exemple)
API_URL = "https://api.nvidia.partners/edge/product/search?page=1&limit=100&locale=fr-fr&Manufacturer=Nvidia"
# GPUs à surveiller
GPU_TARGETS = ["RTX 5070 Ti", "RTX 5070", "RTX 5080", "RTX 5090"]
# Entêtes HTTP pour la requête
# Entêtes HTTP
HEADERS = {
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/131.0.0.0 Safari/537.36",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,"
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,"
"image/avif,image/webp,image/apng,*/*;q=0.8",
"Accept-Encoding": "gzip, deflate, br, zstd",
"Accept-Language": "en-US,en;q=0.5",
@ -51,89 +73,248 @@ HEADERS = {
"Sec-GPC": "1",
}
# Dictionnaire stockant l'état de stock pour chaque GPU.
stock_status = {gpu.upper(): False for gpu in GPU_TARGETS}
# Session avec retries
session = requests.Session()
retries = Retry(total=5, backoff_factor=1, status_forcelist=[500, 502, 503, 504])
session.mount('https://', HTTPAdapter(max_retries=retries))
# Stockage de l'état des stocks
global_stock_status = {}
def send_discord_notification(message: str):
"""Envoie un message sur un salon Discord via un webhook."""
payload = {
"content": message
# Stocke le dernier SKU connu
last_sku = None
first_run = True # Before calling check_rtx_50_founders
# Notifications Discord
def send_discord_notification(gpu_name: str, product_link: str, products_price: str):
# Récupérer le timestamp UNIX actuel
timestamp_unix = int(time.time())
if TEST_MODE:
logging.info(f"[TEST MODE] Notification Discord: {gpu_name} disponible !")
return
embed = {
"title": f"🚀 {PRODUCT_NAME} EN STOCK !",
"color": 3066993,
"thumbnail": {
"url": "https://git.djeex.fr/Djeex/nvidia-stock-bot/raw/branch/main/assets/img/RTX5000.jpg"
},
"author": {
"name": "Nvidia Founder Editions"
},
"fields": [
{
"name": "Prix",
"value": f"`{products_price}€`",
"inline": True
},
{
"name": "Heure",
"value": f"<t:{timestamp_unix}:d> <t:{timestamp_unix}:T>",
"inline": True
},
],
"description": f"**:point_right: [Acheter maintenant]({product_link})**",
"footer": {
"text": "NviBot • JV Hardware 2.0",
"icon_url": "https://git.djeex.fr/Djeex/nvidia-stock-bot/raw/branch/main/assets/img/ds_wh_pp.jpg"
}
}
payload = {"content": "@everyone", "username": "NviBot", "avatar_url": "https://git.djeex.fr/Djeex/nvidia-stock-bot/raw/branch/main/assets/img/ds_wh_pp.jpg", "embeds": [embed]}
try:
response = requests.post(DISCORD_WEBHOOK_URL, json=payload)
if response.status_code == 204:
logging.info("Notification envoyée sur Discord.")
logging.info("Notification envoyée sur Discord.")
else:
logging.error(f"Échec de l'envoi du webhook : {response.status_code} - {response.text}")
logging.error(f"❌ Erreur Webhook : {response.status_code} - {response.text}")
except Exception as e:
logging.error(f"Erreur lors de l'appel au webhook Discord : {e}")
logging.error(f"🚨 Erreur lors de l'envoi du webhook : {e}")
def send_out_of_stock_notification(gpu_name: str, product_link: str, products_price: str):
# Récupérer le timestamp UNIX actuel
timestamp_unix = int(time.time())
def check_rtx_50_founders():
"""Vérifie l'état de stock des GPU Founders Edition et notifie Discord si un GPU repasse en stock."""
if TEST_MODE:
logging.info(f"[TEST MODE] Notification Discord: {gpu_name} hors stock !")
return
embed = {
"title": f"{PRODUCT_NAME} n'est plus en stock",
"color": 15158332, # Rouge pour hors stock
"thumbnail": {
"url": "https://git.djeex.fr/Djeex/nvidia-stock-bot/raw/branch/main/assets/img/RTX5000.jpg"
},
"url": f"{product_link}",
"author": {
"name": "Nvidia Founder Editions"
},
"footer": {
"text": "NviBot • JV Hardware 2.0",
"icon_url": "https://git.djeex.fr/Djeex/nvidia-stock-bot/raw/branch/main/assets/img/ds_wh_pp.jpg"
},
"fields": [
{
"name": "Heure",
"value": f"<t:{timestamp_unix}:d> <t:{timestamp_unix}:T>",
"inline": True
}
]
}
payload = {"username": "NviBot", "avatar_url": "https://git.djeex.fr/Djeex/nvidia-stock-bot/raw/branch/main/assets/img/ds_wh_pp.jpg", "embeds": [embed]}
try:
session.get("https://api.nvidia.partners/edge/product/search?page=1&limit=1",
headers=HEADERS,
timeout=10)
response = requests.post(DISCORD_WEBHOOK_URL, json=payload)
if response.status_code == 204:
logging.info("✅ Notification 'hors stock' envoyée sur Discord.")
else:
logging.error(f"❌ Erreur Webhook : {response.status_code} - {response.text}")
except Exception as e:
logging.error(f"🚨 Erreur lors de l'envoi du webhook : {e}")
response = session.get(API_URL, headers=HEADERS, timeout=10)
logging.info(f"Réponse de l'API : {response.status_code}")
def send_sku_change_notification(old_sku: str, new_sku: str, product_link: str):
# Récupérer le timestamp UNIX actuel
timestamp_unix = int(time.time())
if TEST_MODE:
logging.info(f"[TEST MODE] Changement de SKU détecté : {old_sku}{new_sku}")
return
embed = {
"title": f"🔄 {PRODUCT_NAME} Changement de SKU détecté",
"url": f"{product_link}",
"description": f"**Ancien SKU** : `{old_sku}`\n**Nouveau SKU** : `{new_sku}`",
"color": 16776960, # Jaune
"footer": {
"text": "NviBot • JV Hardware 2.0",
"icon_url": "https://git.djeex.fr/Djeex/nvidia-stock-bot/raw/branch/main/assets/img/ds_wh_pp.jpg"
},
"fields": [
{
"name": "Heure",
"value": f"<t:{timestamp_unix}:d> <t:{timestamp_unix}:T>",
"inline": True
}
]
}
payload = {
"content": "@everyone ⚠️ Potentiel drop imminent !",
"username": "NviBot",
"avatar_url": "https://git.djeex.fr/Djeex/nvidia-stock-bot/raw/branch/main/assets/img/ds_wh_pp.jpg",
"embeds": [embed]
}
try:
response = requests.post(DISCORD_WEBHOOK_URL, json=payload)
if response.status_code == 204:
logging.info("✅ Notification de changement de SKU envoyée sur Discord.")
else:
logging.error(f"❌ Erreur Webhook : {response.status_code} - {response.text}")
except Exception as e:
logging.error(f"🚨 Erreur lors de l'envoi du webhook : {e}")
# Recherche du stock
def check_rtx_50_founders():
global global_stock_status, last_sku, first_run
# Appel vers l'API produit pour récupérer le sku et l'upc
try:
response = session.get(API_URL_SKU, headers=HEADERS, timeout=10)
logging.info(f"Réponse de l'API SKU : {response.status_code}")
response.raise_for_status()
data = response.json()
except requests.exceptions.ReadTimeout:
logging.info("Time-out lors de l'appel API.")
return
except Exception as e:
logging.info(f"Erreur lors de l'appel API : {e}")
except requests.exceptions.RequestException as e:
logging.error(f"Erreur API SKU : {e}")
return
products = data.get("searchedProducts", {}).get("productDetails", [])
product_details = data['searchedProducts']['productDetails'][0]
product_sku = product_details['productSKU']
# Vérifier si c'est la première exécution
if last_sku is not None and product_sku != last_sku:
if not first_run: # Évite d'envoyer une notification au premier appel
product_link = PRODUCT_URL
logging.warning(f"⚠️ SKU modifié : {last_sku}{product_sku}")
send_sku_change_notification(last_sku, product_sku, product_link)
# Mettre à jour le SKU stocké
last_sku = product_sku
first_run = False # Désactive la protection après la première exécution
product_details = data['searchedProducts']['productDetails'][0]
product_sku = product_details['productSKU']
product_upc = product_details.get('productUPC', "")
if not isinstance(product_upc, list):
product_upc = [product_upc]
# Construction de l'url de l'API de stock et appel pour vérifier le statut
API_URL = API_URL_STOCK + product_sku
logging.info(f"URL de l'API de stock appelée : {API_URL}")
try:
response = session.get(API_URL, headers=HEADERS, timeout=10)
logging.info(f"Réponse de l'API : {response.status_code}")
response.raise_for_status()
data = response.json()
except requests.exceptions.RequestException as e:
logging.error(f"Erreur API Stock : {e}")
return
products = data.get("listMap", [])
products_price = 'Prix non disponible' # Valeur par défaut
# Vérification de la liste des produits et récupération du prix
if isinstance(products, list) and len(products) > 0:
for product in products:
price = product.get("price", 'Prix non disponible')
if price != 'Prix non disponible':
products_price = price # Utiliser le prix trouvé
break # Sortir dès qu'on trouve un prix
else:
logging.error("La liste des produits est vide ou mal formée.")
found_in_stock = set()
# Recherche du statut et notifications selon le statut
for p in products:
gpu_name = p.get("gpu", "").upper()
is_founder = p.get("isFounderEdition") is True
is_nvidia = (p.get("manufacturer") == "NVIDIA")
is_buy_now = (p.get("prdStatus") == "buy_now" or p.get("productAvailable") is True)
gpu_name = p.get("fe_sku", "").upper()
is_active = p.get("is_active") == "true"
if is_active and any(target.upper() in gpu_name for target in product_upc):
found_in_stock.add(gpu_name)
if is_founder and is_nvidia and is_buy_now:
if any(target.upper() in gpu_name for target in GPU_TARGETS):
found_in_stock.add(gpu_name)
for gpu in GPU_TARGETS:
for gpu in product_upc:
gpu_upper = gpu.upper()
currently_in_stock = (gpu_upper in found_in_stock)
previously_in_stock = stock_status[gpu_upper]
currently_in_stock = gpu_upper in found_in_stock
previously_in_stock = global_stock_status.get(gpu_upper, False)
if currently_in_stock and not previously_in_stock:
for product in products:
product_name = product.get("gpu", "").upper()
if product_name == gpu_upper:
real_gpu_name = product.get("gpu", "Inconnu")
product_link = product.get("internalLink", "(pas de lien trouvé)")
msg = (
f"@everyone **Disponibilité repérée !**\n"
f"Carte RTX Founders Edition détectée : `{real_gpu_name}`\n"
f"Lien : {product_link}"
)
send_discord_notification(msg)
stock_status[gpu_upper] = True
print(f"{gpu} est maintenant en stock!")
elif (not currently_in_stock) and previously_in_stock:
product_link = PRODUCT_URL
send_discord_notification(gpu_upper, product_link, products_price)
global_stock_status[gpu_upper] = True
logging.info(f"{gpu} est maintenant en stock!")
elif not currently_in_stock and previously_in_stock:
product_link = PRODUCT_URL
send_out_of_stock_notification(gpu_upper, product_link, products_price)
global_stock_status[gpu_upper] = False
logging.info(f"{gpu} n'est plus en stock.")
stock_status[gpu_upper] = False
print(f"{gpu} est hors stock !")
elif not currently_in_stock:
print(f"{gpu} est actuellement hors stock.")
elif currently_in_stock and previously_in_stock:
logging.info(f"{gpu} est actuellement en stock.")
else:
logging.info(f"{gpu} est actuellement hors stock.")
# Boucle
if __name__ == "__main__":
while True:
check_rtx_50_founders()