11 Commits
v2.4 ... wip

Author SHA1 Message Date
bfd8428073 Fixed logo 2025-06-03 13:19:02 +00:00
b0eef8b8df Logo translated 2025-06-03 13:17:10 +00:00
e2d86cb787 Fully translated 2025-06-03 12:58:34 +00:00
8124ad6a2d In english please 2025-06-03 12:41:49 +00:00
27966c04e5 Merge pull request 'Correction structure, orthographe, emoji' (#8) from wip into main
Reviewed-on: #8
2025-04-24 12:53:48 +02:00
17ade38bcd Correction structure, orthographe, emoji 2025-04-24 10:51:52 +00:00
2f8ae16533 Merge pull request 'Correction variables par défaut' (#7) from wip into main
Reviewed-on: #7
2025-04-23 21:12:32 +02:00
80fe61f91d Minor changes 2025-04-23 18:58:15 +00:00
f07ff328e5 Merge pull request 'wip' (#6) from wip into main
Reviewed-on: #6
2025-04-23 19:00:54 +02:00
6657c03b07 Minor changes 2025-04-23 16:59:04 +00:00
9dae286965 Mise à jour de la documentation 2025-04-23 16:57:35 +00:00
7 changed files with 198 additions and 186 deletions

View File

@ -16,7 +16,7 @@ RUN pip install --no-cache-dir -r requirements.txt
# Définir les variables d'environnement par défaut (modifiable lors du lancement du conteneur)
ENV DISCORD_WEBHOOK_URL="https://example.com/webhook" \
REFRESH_TIME="60"
REFRESH_TIME="30"
# Exposer un point de commande pour exécuter le script
CMD ["python", "nvidia-stock-bot.py"]

136
README.md
View File

@ -1,143 +1,148 @@
<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">
<img src="https://img.shields.io/badge/JV%20hardware-join-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>
</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.
**🤖 Nvidia Stock Bot** - A bot that alerts you in real-time about **Nvidia RTX FE** GPU stock availability through Discord notifications.
*Le code a été en partie rédigé et structuré à l'aide d'une IA générative.*
*The code was partially written and structured using a generative AI.*
## Sommaire
## 📌 Table of Contents
- [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)
- [✨ Features](#features)
- [🐳 Docker Installation without cloning the repo (quick)](#docker-installation-without-the-repo-quick)
- [🐙 Docker Installation with the repo (developer)](#docker-installation-with-the-repo)
- [🐍 Python Installation (developer)](#python-installation)
- [🖼️ Screenshots](#screenshots)
- [🧑‍💻 Contributors](#contributors)
## Fonctionnalités
## ✨ Features
- 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
- Discord `@everyone` notification on SKU change (possible imminent drop)
- Discord `@everyone` notification when stock is detected, including model, price, and link
- Silent Discord notification when no stock is detected
- Selectable check frequency
- Selectable GPU model
<img src="https://git.djeex.fr/Djeex/nvidia-stock-bot/raw/branch/main/assets/img/nvbot_schematics.png" align="center">
## 🐳 Docker Installation without the repo (quick)
## Installation sans le dépot avec docker compose
Below are the instructions to set up the container using our pre-built image. With this setup, your bot will run independently as long as the container is active.
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**
**Requirements**
- [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 :
- Create a folder named `nvidia-stock-bot`
- Create a `compose.yaml` file inside that folder with the following content:
```yaml
version: "3.8"
services:
nvidia-stock-bot:
image: git.djeex.fr/djeex/nvidia-stock-bot:latest
container_name: nvidia-stock-bot
restart: always
restart: unless-stopped
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
- DISCORD_WEBHOOK_URL= # Your Discord webhook URL
- PRODUCT_NAME= # Exact GPU name like "RTX 5080"
- PYTHONUNBUFFERED=1 # Enables real-time log output
command: python nvidia-stock-bot.py
```
**Lancer l'image**
**Environment Variables:**
Rendez-vous dans le dossier `nvidia-stock-bot` et lancez le conteneur :
| Variable | Description | Possible Values | Default Value |
|---------------------|-------------------------------------------------|------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------|
| DISCORD_WEBHOOK_URL | Your Discord webhook URL | A valid URL | |
| REFRESH_TIME | Script refresh interval in seconds | `60`, `30`, etc. | `30` |
| API_URL_SKU | API listing the product | A URL | `https://api.nvidia.partners/edge/product/search?page=1&limit=100&locale=fr-fr&Manufacturer=Nvidia` |
| API_URL_STOCK | API providing stock data | A URL | `https://api.store.nvidia.com/partner/v1/feinventory?locale=fr-fr&skus=` |
| PRODUCT_URL | GPU purchase URL | A URL | `https://marketplace.nvidia.com/fr-fr/consumer/graphics-cards/?locale=fr-fr&page=1&limit=12&manufacturer=NVIDIA` |
| PRODUCT_NAME | The exact GPU name you're searching for | `RTX 5090`, `RTX 5080`, `RTX 5070` | |
| TEST_MODE | For testing without sending notifications | `True`, `False` | `False` |
| PYTHONUNBUFFERED | Enables real-time log output | `1`, `0` | `1` |
**Run the image**
Navigate to the `nvidia-stock-bot` folder and launch the container:
```sh
docker compose up -d
```
**Voir les logs pour vérifier le bon fonctionnement**
**Check logs to verify operation**
```sh
docker logs -f nvidia-stock-bot
```
## Installation avec le dépot
## 📦 Docker Installation with the repo
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.
Instructions below show how to install the repo, build the Docker image, and launch the container. Your bot will run independently as long as the container is active.
**Pré-requis**
**Requirements**
- [Git](https://git-scm.com/docs)
- [Docker](https://docs.docker.com/engine/install/)
**Cloner et paramétrer**
**Clone and configure**
- Clonez le repo :
- Clone the repo:
```sh
git clone https://git.djeex.fr/Djeex/nvidia-stock-bot.git
```
- Rendez vous dans le dossier `nvidia-stock-bot` et compilez l'image docker :
- Navigate to `nvidia-stock-bot` and build the Docker image:
```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)
- Then go to `nvidia-stock-bot/docker` and edit the `.env` file with:
- Your Discord webhook URL
- The API and product URLs
- Stock checking frequency (default: 60s; lowering too much may get your IP blocked by Nvidia)
**Lancer l'image**
**Run the image**
Rendez-vous dans le dossier `nvidia-stock-bot/docker` et lancez le conteneur :
Navigate to `nvidia-stock-bot/docker` and launch the container:
```sh
docker compose up -d
```
**Voir les logs pour vérifier le bon fonctionnement**
**Check logs to verify operation**
```sh
docker logs -f nvidia-stock-bot
```
## Installation avec Python
## 🐍 Python Installation
Vous trouverez ci-dessous comment exécuter directement le script Python. Avec cette solution, le bot s'arretera si vous fermez votre terminal.
Instructions to directly run the Python script. Note: the bot stops when you close the terminal.
**Pré-requis**
**Requirements**
- Python 3.11 ou plus
- Python 3.11 or newer
- 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 :
- Create a virtual environment (e.g., `python3 -m venv env_name`)
- Create and navigate into a folder
- Download the Python script:
```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 :
- Export the environment variables with your webhook and refresh time:
```sh
export DISCORD_WEBHOOK_URL="https://votre_url_discord"
export DISCORD_WEBHOOK_URL="https://your_discord_url"
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="
@ -145,21 +150,22 @@ Vous trouverez ci-dessous comment exécuter directement le script Python. Avec c
export PRODUCT_NAME="RTX 5080"
export TEST_MODE=false
```
- Lancez le script
- Run the script
```sh
python nvidia-stock-bot.py
```
## Captures d'écran
## 🖼️ Screenshots
<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">
<img src="https://git.djeex.fr/Djeex/nvidia-stock-bot/raw/branch/main/assets/img/nvidia-stock-bot-discord.png" alt="Nvidia Stock Bot - screenshots">
</div>
## Contributeurs
## 🧑‍💻 Contributors
On remercie pour leurs contributions :
Thanks for their contributions:
- Djeex
- KevOut

Binary file not shown.

Before

Width:  |  Height:  |  Size: 499 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

View File

@ -1,6 +1,6 @@
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
DS_HOOK= # Your Discord webhook URL
FREQ= # Refresh frequency in seconds, default is 30
API_URL_SKU= # API listing the product, default is https://api.nvidia.partners/edge/product/search?page=1&limit=100&locale=fr-fr&Manufacturer=Nvidia
API_URL_STOCK= # API used to check stock without specifying the SKU, default is https://api.store.nvidia.com/partner/v1/feinventory?locale=fr-fr&skus=
PRODUCT_URL= # Purchase URL of the GPU
PRODUCT_NAME= # The exact name of the GPU you're looking for, e.g., "RTX 5080"

View File

@ -1,9 +1,8 @@
version: "3.8"
services:
nvidia-stock-bot:
image: nvidia-stock-bot
container_name: nvidia-stock-bot
restart: always # Le conteneur redémarrera automatiquement en cas d'échec
restart: unless-stopped
env_file:
- .env
environment:
@ -11,5 +10,7 @@ services:
- 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 nvidia-stock-bot.py # Lance le script Python
- PRODUCT_URL=${PRODUCT_URL}
- PRODUCT_NAME=${PRODUCT_NAME}
- PYTHONUNBUFFERED=1 # Allow to display log in real-time
command: python nvidia-stock-bot.py # Run the script

View File

@ -5,56 +5,65 @@ import os
import re
from requests.adapters import HTTPAdapter, Retry
# Configuration du logger
# Logger configuration
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s [%(levelname)s] %(message)s",
)
logging.info("Démarrage du script")
logging.info("Script started")
# Récupération des variables d'environnement
# Retrieve environment variables
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
DISCORD_WEBHOOK_URL = os.environ.get('DISCORD_WEBHOOK_URL')
API_URL_SKU = os.environ.get('API_URL_SKU', 'https://api.nvidia.partners/edge/product/search?page=1&limit=100&locale=fr-fr&Manufacturer=Nvidia')
API_URL_STOCK = os.environ.get('API_URL_STOCK', 'https://api.store.nvidia.com/partner/v1/feinventory?locale=fr-fr&skus=')
REFRESH_TIME = int(os.environ.get('REFRESH_TIME'))
TEST_MODE = os.environ.get('TEST_MODE', 'False').lower() == 'true'
PRODUCT_URL = os.environ['PRODUCT_URL']
PRODUCT_NAME = os.environ['PRODUCT_NAME']
PRODUCT_URL = os.environ.get('PRODUCT_URL', 'https://marketplace.nvidia.com/fr-fr/consumer/graphics-cards/?locale=fr-fr&page=1&limit=12&manufacturer=NVIDIA')
PRODUCT_NAME = os.environ.get('PRODUCT_NAME')
# Regex pour extraire l'ID et le token
# Error logging
if not DISCORD_WEBHOOK_URL:
logging.error("❌ DISCORD_WEBHOOK_URL is required but not defined.")
exit(1)
if not PRODUCT_NAME:
logging.error("❌ PRODUCT_NAME is required but not defined.")
exit(1)
# Regex to extract ID and 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
# Mask last characters of the ID
masked_webhook_id = webhook_id[:len(webhook_id) - 10] + '*' * 10
# Masquer derniers caractères du token
# Mask last characters of the token
masked_webhook_token = webhook_token[:len(webhook_token) - 120] + '*' * 10
# Reconstruction de l'url masquée
# Rebuild masked URL
wh_masked_url = f"https://discord.com/api/webhooks/{masked_webhook_id}/{masked_webhook_token}"
# Error logging
except KeyError as e:
logging.error(f"Variable d'environnement manquante : {e}")
logging.error(f"Missing environment variable: {e}")
exit(1)
except ValueError:
logging.error("REFRESH_TIME doit être un entier valide.")
logging.error("REFRESH_TIME must be a valid integer.")
exit(1)
# Affichage des URLs et configurations
# Display URLs and 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}")
logging.info(f"Discord Webhook URL: {wh_masked_url}")
logging.info(f"API URL SKU: {API_URL_SKU}")
logging.info(f"API URL Stock: {API_URL_STOCK}")
logging.info(f"Product URL: {PRODUCT_URL}")
logging.info(f"Refresh time: {REFRESH_TIME} seconds")
logging.info(f"Test Mode: {TEST_MODE}")
# Entêtes HTTP
# HTTP headers
HEADERS = {
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
@ -73,30 +82,30 @@ HEADERS = {
"Sec-GPC": "1",
}
# Session avec retries
# Session with 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
# Store stock status
global_stock_status = {}
# Stocke le dernier SKU connu
# Store the last known SKU
last_sku = None
first_run = True # Before calling check_rtx_50_founders
# Notifications Discord
# Discord notifications
def send_discord_notification(gpu_name: str, product_link: str, products_price: str):
# Récupérer le timestamp UNIX actuel
# Get current UNIX timestamp
timestamp_unix = int(time.time())
if TEST_MODE:
logging.info(f"[TEST MODE] Notification Discord: {gpu_name} disponible !")
logging.info(f"[TEST MODE] Discord Notification: {gpu_name} available!")
return
embed = {
"title": f"🚀 {PRODUCT_NAME} EN STOCK !",
"title": f"🚀 {PRODUCT_NAME} IN STOCK!",
"color": 3066993,
"thumbnail": {
"url": "https://git.djeex.fr/Djeex/nvidia-stock-bot/raw/branch/main/assets/img/RTX5000.jpg"
@ -107,18 +116,18 @@ def send_discord_notification(gpu_name: str, product_link: str, products_price:
"fields": [
{
"name": "Prix",
"name": "Price",
"value": f"`{products_price}€`",
"inline": True
},
{
"name": "Heure",
"name": "Time",
"value": f"<t:{timestamp_unix}:d> <t:{timestamp_unix}:T>",
"inline": True
},
],
"description": f"**:point_right: [Acheter maintenant]({product_link})**",
"description": f"**:point_right: [Buy now]({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"
@ -128,24 +137,24 @@ def send_discord_notification(gpu_name: str, product_link: str, products_price:
try:
response = requests.post(DISCORD_WEBHOOK_URL, json=payload)
if response.status_code == 204:
logging.info("✅ Notification envoyée sur Discord.")
logging.info("✅ Notification sent to Discord.")
else:
logging.error(f" Erreur Webhook : {response.status_code} - {response.text}")
logging.error(f"❌ Webhook error: {response.status_code} - {response.text}")
except Exception as e:
logging.error(f"🚨 Erreur lors de l'envoi du webhook : {e}")
logging.error(f"🚨 Error sending webhook: {e}")
def send_out_of_stock_notification(gpu_name: str, product_link: str, products_price: str):
# Récupérer le timestamp UNIX actuel
# Get current UNIX timestamp
timestamp_unix = int(time.time())
if TEST_MODE:
logging.info(f"[TEST MODE] Notification Discord: {gpu_name} hors stock !")
logging.info(f"[TEST MODE] Discord Notification: {gpu_name} out of stock!")
return
embed = {
"title": f"{PRODUCT_NAME} n'est plus en stock",
"color": 15158332, # Rouge pour hors stock
"title": f"{PRODUCT_NAME} is out of stock",
"color": 15158332, # Red for out of stock
"thumbnail": {
"url": "https://git.djeex.fr/Djeex/nvidia-stock-bot/raw/branch/main/assets/img/RTX5000.jpg"
},
@ -161,7 +170,7 @@ def send_out_of_stock_notification(gpu_name: str, product_link: str, products_pr
"fields": [
{
"name": "Heure",
"name": "Time",
"value": f"<t:{timestamp_unix}:d> <t:{timestamp_unix}:T>",
"inline": True
}
@ -171,26 +180,26 @@ def send_out_of_stock_notification(gpu_name: str, product_link: str, products_pr
try:
response = requests.post(DISCORD_WEBHOOK_URL, json=payload)
if response.status_code == 204:
logging.info("Notification 'hors stock' envoyée sur Discord.")
logging.info("'Out of stock' notification sent to Discord.")
else:
logging.error(f" Erreur Webhook : {response.status_code} - {response.text}")
logging.error(f"❌ Webhook error: {response.status_code} - {response.text}")
except Exception as e:
logging.error(f"🚨 Erreur lors de l'envoi du webhook : {e}")
logging.error(f"🚨 Error sending webhook: {e}")
def send_sku_change_notification(old_sku: str, new_sku: str, product_link: str):
# Récupérer le timestamp UNIX actuel
# Get current UNIX timestamp
timestamp_unix = int(time.time())
if TEST_MODE:
logging.info(f"[TEST MODE] Changement de SKU détecté : {old_sku}{new_sku}")
logging.info(f"[TEST MODE] SKU change detected: {old_sku}{new_sku}")
return
embed = {
"title": f"🔄 {PRODUCT_NAME} Changement de SKU détecté",
"title": f"🔄 {PRODUCT_NAME} SKU change detected",
"url": f"{product_link}",
"description": f"**Ancien SKU** : `{old_sku}`\n**Nouveau SKU** : `{new_sku}`",
"color": 16776960, # Jaune
"description": f"**Old SKU** : `{old_sku}`\n**New SKU** : `{new_sku}`",
"color": 16776960, # Yellow
"footer": {
"text": "NviBot • JV Hardware 2.0",
@ -199,7 +208,7 @@ def send_sku_change_notification(old_sku: str, new_sku: str, product_link: str):
"fields": [
{
"name": "Heure",
"name": "Time",
"value": f"<t:{timestamp_unix}:d> <t:{timestamp_unix}:T>",
"inline": True
}
@ -207,7 +216,7 @@ def send_sku_change_notification(old_sku: str, new_sku: str, product_link: str):
}
payload = {
"content": "@everyone ⚠️ Potentiel drop imminent !",
"content": "@everyone ⚠️ Possible imminent drop!",
"username": "NviBot",
"avatar_url": "https://git.djeex.fr/Djeex/nvidia-stock-bot/raw/branch/main/assets/img/ds_wh_pp.jpg",
"embeds": [embed]
@ -216,90 +225,88 @@ def send_sku_change_notification(old_sku: str, new_sku: str, product_link: str):
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.")
logging.info("SKU change notification sent to Discord.")
else:
logging.error(f" Erreur Webhook : {response.status_code} - {response.text}")
logging.error(f"❌ Webhook error: {response.status_code} - {response.text}")
except Exception as e:
logging.error(f"🚨 Erreur lors de l'envoi du webhook : {e}")
logging.error(f"🚨 Error sending webhook: {e}")
# Recherche du stock
# Stock search
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
# Call product API to retrieve SKU and UPC
try:
response = session.get(API_URL_SKU, headers=HEADERS, timeout=10)
logging.info(f"Réponse de l'API SKU : {response.status_code}")
logging.info(f"SKU API response: {response.status_code}")
response.raise_for_status()
data = response.json()
except requests.exceptions.RequestException as e:
logging.error(f"Erreur API SKU : {e}")
logging.error(f"SKU API error: {e}")
return
# Recherche du produit dont le GPU correspond à PRODUCT_NAME
# Look for product whose GPU matches PRODUCT_NAME
product_details = None
for p in data['searchedProducts']['productDetails']:
gpu_name = p.get("gpu", "").strip()
# Si le GPU correspond exactement à PRODUCT_NAME
# If the GPU matches exactly PRODUCT_NAME
if gpu_name == PRODUCT_NAME.strip():
product_details = p
break # Sortir dès qu'on trouve le bon produit
break # Exit as soon as the correct product is found
if not product_details:
logging.warning(f"⚠️ Aucun produit avec le GPU '{PRODUCT_NAME}' trouvé.")
logging.warning(f"⚠️ No product with GPU '{PRODUCT_NAME}' found.")
return
# Récupérer le SKU pour le GPU trouvé
# Retrieve the SKU for the found GPU
product_sku = product_details['productSKU']
product_upc = product_details.get('productUPC', "")
# Vérifier si c'est la première exécution
# Check if this is the first execution
if last_sku is not None and product_sku != last_sku:
if not first_run: # Évite d'envoyer une notification au premier appel
if not first_run: # Prevent sending notification on first run
product_link = PRODUCT_URL
logging.warning(f"⚠️ SKU modifié : {last_sku}{product_sku}")
logging.warning(f"⚠️ SKU changed: {last_sku}{product_sku}")
send_sku_change_notification(last_sku, product_sku, product_link)
# Mettre à jour le SKU stocké
# Update stored SKU
last_sku = product_sku
first_run = False # Désactive la protection après la première exécution
first_run = False # Disable first-run protection
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
# Build stock API URL and call to check status
API_URL = API_URL_STOCK + product_sku
logging.info(f"URL de l'API de stock appelée : {API_URL}")
logging.info(f"Stock API URL called: {API_URL}")
try:
response = session.get(API_URL, headers=HEADERS, timeout=10)
logging.info(f"Réponse de l'API : {response.status_code}")
logging.info(f"Stock API response: {response.status_code}")
response.raise_for_status()
data = response.json()
except requests.exceptions.RequestException as e:
logging.error(f"Erreur API Stock : {e}")
logging.error(f"Stock API error: {e}")
return
products = data.get("listMap", [])
products_price = 'Prix non disponible' # Valeur par défaut
products_price = 'Price not available' # Default value
# Vérification de la liste des produits et récupération du prix
# Check product list and retrieve price
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
price = product.get("price", 'Price not available')
if price != 'Price not available':
products_price = price # Use found price
break # Stop at first found price
else:
logging.error("La liste des produits est vide ou mal formée.")
logging.error("Product list is empty or malformed.")
found_in_stock = set()
# Recherche du statut et notifications selon le statut
# Check status and send notifications accordingly
for p in products:
gpu_name = p.get("fe_sku", "").upper()
is_active = p.get("is_active") == "true"
@ -315,20 +322,18 @@ def check_rtx_50_founders():
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!")
logging.info(f"{gpu} is now in 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.")
logging.info(f"{gpu} is no longer in stock.")
elif currently_in_stock and previously_in_stock:
logging.info(f"{gpu} est actuellement en stock.")
logging.info(f"{gpu} is currently in stock.")
else:
logging.info(f"{gpu} est actuellement hors stock.")
logging.info(f"{gpu} is currently out of stock.")
# Boucle
# Loop
if __name__ == "__main__":
while True:
check_rtx_50_founders()