#!/bin/env python import requests import argparse import sys import json import pprint from bs4 import BeautifulSoup from nio import AsyncClient, MatrixRoom, RoomMessageText import asyncio # for nio output import logging logging.basicConfig(level=logging.INFO) # Stuff pp = pprint.PrettyPrinter(indent=4) ppe = pprint.PrettyPrinter(indent=4,stream=sys.stderr) # Permanent requests session for speeeed s = requests.Session() # Static site information ## Base URL for all products url_base = "https://www.auer-packaging.com/de/de" ## Mapping between product code and intermediate URL part product_map = { "EG": "Eurobehälter-geschlossen", "DE": "Auflagedeckel-für-Eurobehälter", "SD": "Scharnierdeckel-für-Eurobehälter" } # get available items for a specific config entry # Needs a config entry and current used dict # Returns a dict of { item: count } def auer_bware_getcurrent(entry,used): got = 0 getting = {} if not entry.get("bware"): return None # Test every alternative and for item in entry["alts"]: bitem = f"B-{item}" if got >= entry["qty"]: break available = auer_bware_getcount(item) u = used.get(f"{bitem}",0) print(f"\t{item}: {available-u}/{available}",file=sys.stderr) g = getting.get(f"{bitem}",0) if available is not None: if available - u > 0: totake = entry["qty"] if available - u > entry["qty"] else available - u used[f"{bitem}"] = u + totake getting[f"{bitem}"] = g + totake got += totake print(f'\treserving {totake} of {bitem}',file=sys.stderr) else: print(f"permutation {bitem} not available",file=sys.stderr) return got,getting # Returns integer for available items def auer_bware_getcount(item): try: ret = s.get(auer_tourl(f'B-{item}')) if ret.status_code == 200: content = BeautifulSoup(ret.text,features="lxml") available = int(content.find_all("div", class_="hinweis-cell product-availability")[0].contents[1]) return available else: return None except Exception as e: print(f"Accessing item {item} failed with: {e}",file=sys.stderr) return None # Returns float fot the price for items def auer_item_getprice(item): try: ret = s.get(auer_tourl(item)) if ret.status_code == 200: content = BeautifulSoup(ret.text,features="lxml") if item.startswith("B-"): price_str = content.find_all("span", class_="b-stock-price")[0].contents[0] else: price_str = content.find_all("div", class_="productPricesCell alignright red")[0].contents[0] return float(price_str.split()[0].replace(',','.')) else: return None except Exception as e: print(f"Accessing item {item} failed with: {e}",file=sys.stderr) return None def auer_tourl(item,skip_b=True): pcode = item.split("-")[0] if pcode == "B" and skip_b: pcode = item.split("-")[1] if pcode in product_map.keys(): return f'{url_base}/{product_map[pcode]}/{item}.html' else: return None def auer_request(conf): bware_used = {} ware_used = {} needed = 0 bware_req = 0 ware = 0 bware = 0 for entry in conf: print(f'{entry["name"]}: {entry["qty"]} of {entry["alts"][0]},...',file=sys.stderr) needed += entry["qty"] default = entry["alts"][0] got_bware = 0 getting = {} if entry.get("bware"): bware_req += entry["qty"] got_bware,getting = auer_bware_getcurrent(entry,bware_used) bware += got_bware if got_bware < entry["qty"]: get_ware = entry["qty"] - got_bware ware_used[f'{default}'] = ware_used.get(f'{default}',0) + get_ware ware += get_ware print(f'\tdefaulting to {get_ware} of {default}',file=sys.stderr) unum = 0 print(f"items needed = {needed}") print(f"bware requested = {bware_req}") print(f"bware available = {bware}") pp.pprint(bware_used) print(f"normal ware = {ware}") pp.pprint(ware_used) print(f"{float(bware)/float(needed)*100:.2f}% of all items available as bware") cost_bware = auer_calc_total(bware_used) print(f"total for bware = {cost_bware:.2f}") cost_ware = auer_calc_total(ware_used) print(f"total for ware = {cost_ware:.2f}") return ware_used,bware_used def auer_calc_total(items): total = 0.0 for item,count in items.items(): total = total + count * auer_item_getprice(item) return total async def bot_main(): # Initialize the Matrix client client = AsyncClient("https://matrix.org") # Replace 'your_username', 'your_password', and 'room_id' with your actual Matrix credentials username = "your_username" password = "your_password" room_id = "room_id" await login(client, username, password) # Start the event listener in the background event_listener_task = asyncio.create_task(event_listener()) try: while True: # Send a periodic message every 60 seconds await send_periodic_message(room_id, "Hello, world!") # Sleep for 60 seconds await asyncio.sleep(60) except KeyboardInterrupt: print("Bot stopped by the user.") finally: # Stop the event listener task event_listener_task.cancel() # Close the Matrix client connection await client.close() def main(): used = {} needed = 0 parser = argparse.ArgumentParser() parser.add_argument("-c", help="Filename for json config instead of stdin") parser.add_argument('--bot', action=argparse.BooleanOptionalAction, help="Start in bot mode instead of standalone script") parser.add_argument("-m", help="Filename for matrix bot configuration") args = parser.parse_args() if args.bot: bot_main() else: # parse command line if args.c is not None: inf = open(args.c) else: inf = sys.stdin conf = json.load(inf) ppe.pprint(conf) auer_request(conf) if inf is not sys.stdin: inf.close() if __name__ == "__main__": main()