From 5b438cb2dc02a18f91dabcd1d78d5c8841586f90 Mon Sep 17 00:00:00 2001 From: Esa Jokinen Date: Wed, 31 Jul 2024 13:44:59 +0300 Subject: [PATCH] Add generalized product-pricelimiter.sh Replaces xxl-product-pricelimiter.sh --- README.md | 3 +- bin/product-pricelimiter.sh | 113 ++++++++++++++++++++++++++++++++ bin/xxl-product-pricelimiter.sh | 73 --------------------- 3 files changed, 115 insertions(+), 74 deletions(-) create mode 100755 bin/product-pricelimiter.sh delete mode 100755 bin/xxl-product-pricelimiter.sh diff --git a/README.md b/README.md index fc78840..1318d5e 100644 --- a/README.md +++ b/README.md @@ -18,8 +18,9 @@ Miscellaneous scripts for different purposes. Mostly unrelated to each other. | Infosec
Automation | [`make-mac-prefixes.py`](bin/make-mac-prefixes.py)
Python 3 | Processes registered MAC address prefixes from [IEEE MA-L Assignments (CSV)](https://standards.ieee.org/products-programs/regauth/) (stdin) to Nmap's [`nmap-mac-prefixes`](https://github.com/nmap/nmap/blob/master/nmap-mac-prefixes) (stdout) with a few additional unregistered OUIs.
`curl https://standards-oui.ieee.org/oui/oui.csv \| make-mac-prefixes.py > nmap-mac-prefixes` | | WordPress | [`test-cache-enabler.py`](bin/test-cache-enabler.py)
Python 3 | Tests whether the Cache Enabler by KeyCDN (WordPress) is working properly on the URLs given as arguments.
`test-cache-enabler.py https://example.com [...]` | | Web | [`detect-modified-html-element.sh`](bin/detect-modified-html-element.sh)
Shell (bash) | Checks HTML element changes on a web page since last run. Configured via environment variables.
Recommended to be executed as a SystemD [service](systemd/detect-modified-html-element.service.example). | +| Web | [`product-pricelimiter.sh`](bin/product-pricelimiter.sh)
Shell (bash) | Compare product price on a web page with a given maximum price. Use, e.g., developer tools on your browser to find the HTML element containing the price.
`product-pricelimiter.sh ProductURL Element MaxPrice` | | Web | `koronarokotusaika.sh`
Shell (bash) | This script has been removed as koronarokotusaika.fi (bookcovidvaccine.fi) has been shut down on April 28, 2023. | -| Web | [`xxl-product-pricelimiter.sh`](bin/xxl-product-pricelimiter.sh)
Shell (bash) | XXL.fi product price checker / limiter.
`xxl-product-pricelimiter.sh XXL.fi-ProductURL MaxPrice` | +| Web | `xxl-product-pricelimiter.sh`
Shell (bash) | This script has been replaced by the generalized [`product-pricelimiter.sh`](bin/product-pricelimiter.sh) as the HTML structure of XXL.fi has changed. | ## Scripts that require `sudo` privileges ([`sbin/`](sbin/)) diff --git a/bin/product-pricelimiter.sh b/bin/product-pricelimiter.sh new file mode 100755 index 0000000..563afa6 --- /dev/null +++ b/bin/product-pricelimiter.sh @@ -0,0 +1,113 @@ +#!/bin/bash +read -r -d '' USAGE << EOM +# ------------------------------------------------------------------------------ +# Compare product price on a web page with a given maximum price. +# +# Usage: product-pricelimiter.sh ProductURL Element MaxPrice +# +# ProductURL web page URL to fetch the current price from +# Element the HTML element containing the price (#id or .class) +# MaxPrice float number +# +# Exit codes: +# +# 0 OK Price is found and lower than or equal with the MaxPrice. +# 1 ERROR An error has occured; unable to tell the result. +# 2 WAIT Price is found but higher than the MaxPrice. +# +# Author : Esa Jokinen (oh2fih) +# Home : https://github.com/oh2fih/Misc-Scripts +# ------------------------------------------------------------------------------ +EOM + +# Fake user-agent for curl + +UA="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 " +UA+="(KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36" + +# Test the inputs... + +if [ "$#" -ne 3 ]; then + echo -e "\033[0;33m${USAGE}\033[0m" >&2 + exit 1 +fi + +if [[ "$3" =~ ^[+-]?[0-9]+[\.,]?[0-9]*$ ]] 2>/dev/null; then + producturl="$1" + selector="$2" + maxprice=$(printf "%s" "$3" | sed 's/,/./g') +else + echo -e "\033[0;31mMax price should be a (float) number!\033[0m" >&2 + exit 1 +fi + +# Validate the URL + +regex='(https?)://[-A-Za-z0-9\+&@#/%?=~_|!:,.;]*[-A-Za-z0-9\+&@#/%=~_|]' +if ! [[ $producturl =~ $regex ]]; then + echo -e "\033[0;31mThe first argument was not a valid URL!\033[0m" >&2 + exit 1 +fi + +# Check for requirements. Print all unmet requirements at once. + +required_command() { + if ! command -v "$1" &> /dev/null; then + if [ -z ${2+x} ]; then + echo -e "\033[0;31mThis script requires ${1}!\033[0m" >&2 + else + echo -e "\033[0;31mThis script requires ${1} ${2}!\033[0m" >&2 + fi + ((UNMET=UNMET+1)) + fi +} + +UNMET=0 + +required_command "hxselect" "; Please install html-xml-utils" +required_command "hxnormalize" "; Please install html-xml-utils" +required_command "grep" "for parsing the page content" +required_command "sed" "for converting delimiters" +required_command "curl" "for fetching the web page" +required_command "sort" "for comparing float numbers" +required_command "head" "for comparing float numbers" + +if [ "$UNMET" -gt 0 ]; then + exit 1 +fi + +# Normalize the web page and get the monitored element + +element_contents=$( + curl -A "$UA" -s "$producturl" \ + | hxnormalize -x \ + | hxselect -c "$selector" + ) +if [ "$element_contents" == "" ]; then + echo -e "\033[0;31mFailed to fetch \"$selector\" in ${producturl}\033[0m" >&2 + exit 1 +fi + +# Extract price (first match) from the element and compare it with the limit + +price=$( + echo "$element_contents" \ + | grep -m 1 -Eo '[0-9]+([,\.][0-9]{0,2})?' \ + | sed 's/,/./g' | head -n 1 + ) +if [ "$price" == "" ]; then + echo -e "\033[0;31mPrice not found from \"${selector}\"!\033[0m" >&2 + exit 1 +fi + +lower=$(printf "%s\n%s" "$price" "$maxprice" | sort -g | head -1) + +if [ "$lower" = "$price" ]; then + echo -ne "\033[0;32mGood to buy! " + echo -e "The price in \"$selector\" is now $price €\033[0m" + exit 0 +else + echo -ne "\033[0;33mPlease be patient! " + echo -e "The price in \"$selector\" is still $price €\033[0m" + exit 2 +fi diff --git a/bin/xxl-product-pricelimiter.sh b/bin/xxl-product-pricelimiter.sh deleted file mode 100755 index aff8197..0000000 --- a/bin/xxl-product-pricelimiter.sh +++ /dev/null @@ -1,73 +0,0 @@ -#!/bin/bash -# ------------------------------------------------------------------------------ -# Gets the current product price from a www.xxl.fi product page, compares it -# with a maximum price given and exits with error level 0 if the price is lower -# than the maximum price. -# -# Usage: xxl-product-pricelimiter.sh ProductURL MaxPrice -# -# Author : Esa Jokinen (oh2fih) -# Home : https://github.com/oh2fih/Misc-Scripts -# ------------------------------------------------------------------------------ - -# Test the inputs... -if [ "$#" -ne 2 ]; then - printf "\n\e[33m%s\e[0m\n\n" "Usage: $0 XXL.fi-ProductURL MaxPrice" >&2 - exit 1 -fi - -if [[ "$2" =~ ^[+-]?[0-9]+[\.,]?[0-9]*$ ]] 2>/dev/null; then - producturl="$1" - maxprice=$(printf "%s" "$2"| sed 's/,/./g') -else - printf "\n\e[31m%s\e[0m\n\n" "Max price should be a (float) number!" >&2 - exit 1 -fi - -# Validate the URL -regex='(https?)://[-A-Za-z0-9\+&@#/%?=~_|!:,.;]*[-A-Za-z0-9\+&@#/%=~_|]' -if [[ $producturl =~ $regex ]]; then - - # Download the page and get current price. - productpage=$(curl --silent "$producturl") - - productname=$( - printf "%s" "$productpage" \ - | grep "data\-product\-name" \ - | head -n 1 \ - | grep -o '".*"' \ - | sed 's/"//g' - ) - - productprice=$( - printf "%s" "$productpage" \ - | grep "data\-product\-price" \ - | grep -o '".*"' \ - | sed -e 's/[^0-9,\.]*//g' \ - | sed 's/,/./g' - ) - - if [ -z "$productprice" ]; then - printf "\n\e[31m%s\e[0m\n\n" "Unable to capture product price." >&2 - exit 1 - fi - - lower=$(printf "%s\n%s" "$productprice" "$maxprice" | sort -g | head -1) - - # Compare the prices. - if [ "$lower" = "$productprice" ]; then - printf "\n\e[32m%s\e[0m" "Good to buy! The price of " - printf "\e[32m%s\e[0m\n\n" "\"$productname\" is now $productprice €" - exit 0 - else - printf "\n\e[33m%s\e[0m" "Please be patient! The price of " >&2 - printf "\e[33m%s\e[0m\n\n" "\"$productname\" is still $productprice €" >&2 - exit 1 - fi - -else - - printf "\n\e[31m%s\e[0m\n\n" "The first argument was not a valid URL." >&2 - exit 1 - -fi