The Steam Deck has revolutionized portable PC gaming, offering an exciting way to play your favorite PC games on the go. However, getting your hands on a refurbished model can be challenging due to its limited availability. To solve this, I created a Python-based Steam Deck Availability Checker that monitors stock and notifies users when refurbished Steam Decks are available in Europe.
This guide will walk you through how the project works and explain the Python code step by step so that even beginners can follow along and build their own availability checker.
Project Overview
The Steam Deck Availability Checker is a Python script designed to:
- Periodically check Steam’s store for refurbished Steam Decks using the Steam API.
- Send real-time notifications to you when stock becomes available using the ntfy notification service.
- Run continuously in the background when added to a scheduler like cron (on Linux) or Task Scheduler (on Windows).
This script is a great way to learn about Python, APIs, and automation while building a useful tool.
How It Works
Here’s the workflow of the script:
- Check Stock Availability: The script queries the Steam API to see if a specific refurbished Steam Deck model is available.
- Send a Notification: If stock is detected, the script uses ntfy to send you a notification on your phone or computer.
- Repeat the Process: You can set the script to run periodically, so you’ll be notified as soon as stock appears.
Now, let’s break down the Python code into smaller, easy-to-understand steps.
Step 1: Import the Necessary Module
<span>from</span> <span>urllib.request</span> <span>import</span> <span>urlopen</span><span>from</span> <span>urllib.request</span> <span>import</span> <span>urlopen</span>from urllib.request import urlopen
Enter fullscreen mode Exit fullscreen mode
We use the urllib.request
module, which is built into Python, to send HTTP requests to the Steam API and ntfy. You don’t need to install any additional libraries.
Step 2: Define Important Variables
<span>ntfy_url</span> <span>=</span> <span>"</span><span>ntfy.sh/YOUR_NTFY_URL</span><span>"</span> <span># Replace with your ntfy URL </span><span>timeout</span> <span>=</span> <span>8</span> <span># Timeout to prevent the script from hanging </span><span>ntfy_url</span> <span>=</span> <span>"</span><span>ntfy.sh/YOUR_NTFY_URL</span><span>"</span> <span># Replace with your ntfy URL </span><span>timeout</span> <span>=</span> <span>8</span> <span># Timeout to prevent the script from hanging </span>ntfy_url = "ntfy.sh/YOUR_NTFY_URL" # Replace with your ntfy URL timeout = 8 # Timeout to prevent the script from hanging
Enter fullscreen mode Exit fullscreen mode
-
ntfy_url
: This is the URL for the ntfy notification service. You need to replaceYOUR_NTFY_URL
with your own ntfy channel URL. To set up your channel, go to ntfy.sh and follow the instructions. -
timeout
: This ensures the script doesn’t hang if the Steam API is slow to respond.
Step 3: Check Stock Availability
<span>def</span> <span>parse_availability</span><span>(</span><span>data</span><span>:</span> <span>bytes</span><span>)</span> <span>-></span> <span>bool</span><span>:</span><span>parsed</span> <span>=</span> <span>"</span><span> </span><span>"</span><span>.</span><span>join</span><span>(</span><span>f</span><span>"</span><span>{</span><span>c</span><span>:</span><span>02</span><span>X</span><span>}</span><span>"</span> <span>for</span> <span>c</span> <span>in</span> <span>data</span><span>)</span><span>not_available</span> <span>=</span> <span>"</span><span>08 00 10 00</span><span>"</span><span>return</span> <span>parsed</span> <span>!=</span> <span>not_available</span><span>def</span> <span>parse_availability</span><span>(</span><span>data</span><span>:</span> <span>bytes</span><span>)</span> <span>-></span> <span>bool</span><span>:</span> <span>parsed</span> <span>=</span> <span>"</span><span> </span><span>"</span><span>.</span><span>join</span><span>(</span><span>f</span><span>"</span><span>{</span><span>c</span><span>:</span><span>02</span><span>X</span><span>}</span><span>"</span> <span>for</span> <span>c</span> <span>in</span> <span>data</span><span>)</span> <span>not_available</span> <span>=</span> <span>"</span><span>08 00 10 00</span><span>"</span> <span>return</span> <span>parsed</span> <span>!=</span> <span>not_available</span>def parse_availability(data: bytes) -> bool: parsed = " ".join(f"{c:02X}" for c in data) not_available = "08 00 10 00" return parsed != not_available
Enter fullscreen mode Exit fullscreen mode
- The
parse_availability
function processes the response from the Steam API. It converts the data into a readable format and checks if it matches the code for “not available” (08 00 10 00
). - If the data doesn’t match, it means stock is available.
Step 4: Query the Steam API
<span>def</span> <span>is_available</span><span>(</span><span>id_</span><span>:</span> <span>str</span><span>)</span> <span>-></span> <span>bool</span><span>:</span><span>url</span> <span>=</span> <span>(</span><span>"</span><span>api.steampowered.com/IPhysicalGoodsService/</span><span>"</span><span>"</span><span>CheckInventoryAvailableByPackage/v1?origin=</span><span>"</span><span>f</span><span>"</span><span>https://store.steampowered.com&input_protobuf_encoded=</span><span>{</span><span>id_</span><span>}</span><span>"</span><span>)</span><span>with</span> <span>urlopen</span><span>(</span><span>f</span><span>"</span><span>https://</span><span>{</span><span>url</span><span>}</span><span>"</span><span>,</span> <span>timeout</span><span>=</span><span>timeout</span><span>)</span> <span>as</span> <span>response</span><span>:</span><span>data</span> <span>=</span> <span>response</span><span>.</span><span>read</span><span>()</span><span>return</span> <span>parse_availability</span><span>(</span><span>data</span><span>)</span><span>def</span> <span>is_available</span><span>(</span><span>id_</span><span>:</span> <span>str</span><span>)</span> <span>-></span> <span>bool</span><span>:</span> <span>url</span> <span>=</span> <span>(</span> <span>"</span><span>api.steampowered.com/IPhysicalGoodsService/</span><span>"</span> <span>"</span><span>CheckInventoryAvailableByPackage/v1?origin=</span><span>"</span> <span>f</span><span>"</span><span>https://store.steampowered.com&input_protobuf_encoded=</span><span>{</span><span>id_</span><span>}</span><span>"</span> <span>)</span> <span>with</span> <span>urlopen</span><span>(</span><span>f</span><span>"</span><span>https://</span><span>{</span><span>url</span><span>}</span><span>"</span><span>,</span> <span>timeout</span><span>=</span><span>timeout</span><span>)</span> <span>as</span> <span>response</span><span>:</span> <span>data</span> <span>=</span> <span>response</span><span>.</span><span>read</span><span>()</span> <span>return</span> <span>parse_availability</span><span>(</span><span>data</span><span>)</span>def is_available(id_: str) -> bool: url = ( "api.steampowered.com/IPhysicalGoodsService/" "CheckInventoryAvailableByPackage/v1?origin=" f"https://store.steampowered.com&input_protobuf_encoded={id_}" ) with urlopen(f"https://{url}", timeout=timeout) as response: data = response.read() return parse_availability(data)
Enter fullscreen mode Exit fullscreen mode
-
id_
: This is a unique identifier for the product (e.g., the refurbished 64GB Steam Deck). The script uses it to query the Steam API. -
url
: The API endpoint is constructed using the product ID. - The function sends a request to the Steam API, reads the response, and checks if stock is available by calling
parse_availability
.
Step 5: Send a Notification
<span>def</span> <span>notify</span><span>(</span><span>name</span><span>:</span> <span>str</span><span>)</span> <span>-></span> <span>None</span><span>:</span><span>message</span> <span>=</span> <span>f</span><span>"</span><span>Version </span><span>{</span><span>name</span><span>}</span><span> is now available!</span><span>"</span><span>print</span><span>(</span><span>message</span><span>)</span><span>with</span> <span>urlopen</span><span>(</span><span>f</span><span>"</span><span>https://</span><span>{</span><span>ntfy_url</span><span>}</span><span>"</span><span>,</span> <span>data</span><span>=</span><span>str</span><span>.</span><span>encode</span><span>(</span><span>message</span><span>),</span> <span>timeout</span><span>=</span><span>timeout</span><span>):</span><span>pass</span><span>def</span> <span>notify</span><span>(</span><span>name</span><span>:</span> <span>str</span><span>)</span> <span>-></span> <span>None</span><span>:</span> <span>message</span> <span>=</span> <span>f</span><span>"</span><span>Version </span><span>{</span><span>name</span><span>}</span><span> is now available!</span><span>"</span> <span>print</span><span>(</span><span>message</span><span>)</span> <span>with</span> <span>urlopen</span><span>(</span><span>f</span><span>"</span><span>https://</span><span>{</span><span>ntfy_url</span><span>}</span><span>"</span><span>,</span> <span>data</span><span>=</span><span>str</span><span>.</span><span>encode</span><span>(</span><span>message</span><span>),</span> <span>timeout</span><span>=</span><span>timeout</span><span>):</span> <span>pass</span>def notify(name: str) -> None: message = f"Version {name} is now available!" print(message) with urlopen(f"https://{ntfy_url}", data=str.encode(message), timeout=timeout): pass
Enter fullscreen mode Exit fullscreen mode
- The
notify
function sends a notification to your ntfy channel with the name of the available product (e.g., “64GB Steam Deck”). - The
urlopen
function sends the notification message as data to the ntfy server.
Step 6: Main Script
<span>if</span> <span>__name__</span> <span>==</span> <span>"</span><span>__main__</span><span>"</span><span>:</span><span># Uncomment to test the notifier </span> <span># notify("TEST") </span><span># Refurbished 64GB in Europe, tested in Poland </span> <span>if</span> <span>is_available</span><span>(</span><span>"</span><span>COGVNxICUEw=</span><span>"</span><span>):</span><span>notify</span><span>(</span><span>"</span><span>64GB</span><span>"</span><span>)</span><span>if</span> <span>__name__</span> <span>==</span> <span>"</span><span>__main__</span><span>"</span><span>:</span> <span># Uncomment to test the notifier </span> <span># notify("TEST") </span> <span># Refurbished 64GB in Europe, tested in Poland </span> <span>if</span> <span>is_available</span><span>(</span><span>"</span><span>COGVNxICUEw=</span><span>"</span><span>):</span> <span>notify</span><span>(</span><span>"</span><span>64GB</span><span>"</span><span>)</span>if __name__ == "__main__": # Uncomment to test the notifier # notify("TEST") # Refurbished 64GB in Europe, tested in Poland if is_available("COGVNxICUEw="): notify("64GB")
Enter fullscreen mode Exit fullscreen mode
- This section is the script’s starting point.
- Uncomment the
notify("TEST")
line to test your ntfy setup. - The
is_available
function checks if the refurbished 64GB model is in stock using the product IDCOGVNxICUEw=
. If it is, the script sends a notification.
Final Script
<span>from</span> <span>urllib.request</span> <span>import</span> <span>urlopen</span><span># Set this </span><span>ntfy_url</span> <span>=</span> <span>"</span><span>ntfy.sh/YOUR_NTFY_URL</span><span>"</span><span># We need a timeout to prevent script from hanging </span><span>timeout</span> <span>=</span> <span>8</span><span>def</span> <span>parse_availability</span><span>(</span><span>data</span><span>:</span> <span>bytes</span><span>)</span> <span>-></span> <span>bool</span><span>:</span><span>parsed</span> <span>=</span> <span>"</span><span> </span><span>"</span><span>.</span><span>join</span><span>(</span><span>f</span><span>"</span><span>{</span><span>c</span><span>:</span><span>02</span><span>X</span><span>}</span><span>"</span> <span>for</span> <span>c</span> <span>in</span> <span>data</span><span>)</span><span>not_available</span> <span>=</span> <span>"</span><span>08 00 10 00</span><span>"</span><span>return</span> <span>parsed</span> <span>!=</span> <span>not_available</span><span>def</span> <span>is_available</span><span>(</span><span>id_</span><span>:</span> <span>str</span><span>)</span> <span>-></span> <span>bool</span><span>:</span><span>url</span> <span>=</span> <span>(</span><span>"</span><span>api.steampowered.com/IPhysicalGoodsService/</span><span>"</span><span>"</span><span>CheckInventoryAvailableByPackage/v1?origin=</span><span>"</span><span>f</span><span>"</span><span>https://store.steampowered.com&input_protobuf_encoded=</span><span>{</span><span>id_</span><span>}</span><span>"</span><span>)</span><span>with</span> <span>urlopen</span><span>(</span><span>f</span><span>"</span><span>https://</span><span>{</span><span>url</span><span>}</span><span>"</span><span>,</span> <span>timeout</span><span>=</span><span>timeout</span><span>)</span> <span>as</span> <span>response</span><span>:</span><span>data</span> <span>=</span> <span>response</span><span>.</span><span>read</span><span>()</span><span>return</span> <span>parse_availability</span><span>(</span><span>data</span><span>)</span><span>def</span> <span>notify</span><span>(</span><span>name</span><span>:</span> <span>str</span><span>)</span> <span>-></span> <span>None</span><span>:</span><span>message</span> <span>=</span> <span>f</span><span>"</span><span>Version </span><span>{</span><span>name</span><span>}</span><span> is now available!</span><span>"</span><span>print</span><span>(</span><span>message</span><span>)</span><span>with</span> <span>urlopen</span><span>(</span><span>f</span><span>"</span><span>https://</span><span>{</span><span>ntfy_url</span><span>}</span><span>"</span><span>,</span> <span>data</span><span>=</span><span>str</span><span>.</span><span>encode</span><span>(</span><span>message</span><span>),</span> <span>timeout</span><span>=</span><span>timeout</span><span>):</span><span>pass</span><span>if</span> <span>__name__</span> <span>==</span> <span>"</span><span>__main__</span><span>"</span><span>:</span><span># Uncomment to test the notifier </span> <span># notify("TEST") </span><span># Refurbished 64GB in Europe, tested in Poland </span> <span>if</span> <span>is_available</span><span>(</span><span>"</span><span>COGVNxICUEw=</span><span>"</span><span>):</span><span>notify</span><span>(</span><span>"</span><span>64GB</span><span>"</span><span>)</span><span>from</span> <span>urllib.request</span> <span>import</span> <span>urlopen</span> <span># Set this </span><span>ntfy_url</span> <span>=</span> <span>"</span><span>ntfy.sh/YOUR_NTFY_URL</span><span>"</span> <span># We need a timeout to prevent script from hanging </span><span>timeout</span> <span>=</span> <span>8</span> <span>def</span> <span>parse_availability</span><span>(</span><span>data</span><span>:</span> <span>bytes</span><span>)</span> <span>-></span> <span>bool</span><span>:</span> <span>parsed</span> <span>=</span> <span>"</span><span> </span><span>"</span><span>.</span><span>join</span><span>(</span><span>f</span><span>"</span><span>{</span><span>c</span><span>:</span><span>02</span><span>X</span><span>}</span><span>"</span> <span>for</span> <span>c</span> <span>in</span> <span>data</span><span>)</span> <span>not_available</span> <span>=</span> <span>"</span><span>08 00 10 00</span><span>"</span> <span>return</span> <span>parsed</span> <span>!=</span> <span>not_available</span> <span>def</span> <span>is_available</span><span>(</span><span>id_</span><span>:</span> <span>str</span><span>)</span> <span>-></span> <span>bool</span><span>:</span> <span>url</span> <span>=</span> <span>(</span> <span>"</span><span>api.steampowered.com/IPhysicalGoodsService/</span><span>"</span> <span>"</span><span>CheckInventoryAvailableByPackage/v1?origin=</span><span>"</span> <span>f</span><span>"</span><span>https://store.steampowered.com&input_protobuf_encoded=</span><span>{</span><span>id_</span><span>}</span><span>"</span> <span>)</span> <span>with</span> <span>urlopen</span><span>(</span><span>f</span><span>"</span><span>https://</span><span>{</span><span>url</span><span>}</span><span>"</span><span>,</span> <span>timeout</span><span>=</span><span>timeout</span><span>)</span> <span>as</span> <span>response</span><span>:</span> <span>data</span> <span>=</span> <span>response</span><span>.</span><span>read</span><span>()</span> <span>return</span> <span>parse_availability</span><span>(</span><span>data</span><span>)</span> <span>def</span> <span>notify</span><span>(</span><span>name</span><span>:</span> <span>str</span><span>)</span> <span>-></span> <span>None</span><span>:</span> <span>message</span> <span>=</span> <span>f</span><span>"</span><span>Version </span><span>{</span><span>name</span><span>}</span><span> is now available!</span><span>"</span> <span>print</span><span>(</span><span>message</span><span>)</span> <span>with</span> <span>urlopen</span><span>(</span><span>f</span><span>"</span><span>https://</span><span>{</span><span>ntfy_url</span><span>}</span><span>"</span><span>,</span> <span>data</span><span>=</span><span>str</span><span>.</span><span>encode</span><span>(</span><span>message</span><span>),</span> <span>timeout</span><span>=</span><span>timeout</span><span>):</span> <span>pass</span> <span>if</span> <span>__name__</span> <span>==</span> <span>"</span><span>__main__</span><span>"</span><span>:</span> <span># Uncomment to test the notifier </span> <span># notify("TEST") </span> <span># Refurbished 64GB in Europe, tested in Poland </span> <span>if</span> <span>is_available</span><span>(</span><span>"</span><span>COGVNxICUEw=</span><span>"</span><span>):</span> <span>notify</span><span>(</span><span>"</span><span>64GB</span><span>"</span><span>)</span>from urllib.request import urlopen # Set this ntfy_url = "ntfy.sh/YOUR_NTFY_URL" # We need a timeout to prevent script from hanging timeout = 8 def parse_availability(data: bytes) -> bool: parsed = " ".join(f"{c:02X}" for c in data) not_available = "08 00 10 00" return parsed != not_available def is_available(id_: str) -> bool: url = ( "api.steampowered.com/IPhysicalGoodsService/" "CheckInventoryAvailableByPackage/v1?origin=" f"https://store.steampowered.com&input_protobuf_encoded={id_}" ) with urlopen(f"https://{url}", timeout=timeout) as response: data = response.read() return parse_availability(data) def notify(name: str) -> None: message = f"Version {name} is now available!" print(message) with urlopen(f"https://{ntfy_url}", data=str.encode(message), timeout=timeout): pass if __name__ == "__main__": # Uncomment to test the notifier # notify("TEST") # Refurbished 64GB in Europe, tested in Poland if is_available("COGVNxICUEw="): notify("64GB")
Enter fullscreen mode Exit fullscreen mode
Running the Script
Here’s how to get started:
- Install Python: Ensure you have a recent version of Python installed on your computer. You can download it from python.org.
- Set Your ntfy URL: Replace
ntfy_url
in the script with your own URL. Follow the instructions on ntfy.sh to set up your notification channel and install the app on your phone (optional). - Run the Script: Save the code to a file (e.g.,
steam_deck_checker.py
) and run it using Python:
python steam_deck_checker.pypython steam_deck_checker.pypython steam_deck_checker.py
Enter fullscreen mode Exit fullscreen mode
Additional Notes
- On Windows Server, you might need to add
ntfy.sh
andapi.steampowered.com
to your trusted sites in IE settings for the script to work properly. - To run the script periodically, add it to Task Scheduler (Windows) or cron (Linux).
Conclusion
The Steam Deck Availability Checker is a simple yet powerful project that uses Python to solve a real-world problem. It’s beginner-friendly and teaches you how to work with APIs, automate tasks, and send notifications.
Feel free to check out the GitHub repository for the complete code. You can contribute to the project or customize it to monitor other products.
Happy coding!
原文链接:Building an Availability Checker for Refurbished Steam Decks in Europe
暂无评论内容