pass list name + refactor

This commit is contained in:
Yashar Dabiran 2025-02-15 23:01:03 -05:00
parent 8cc00144fa
commit ef86244cc5
3 changed files with 115 additions and 81 deletions

105
main.py
View file

@ -1,70 +1,113 @@
import aiohttp """Bring! TRMNL plugin"""
import asyncio import asyncio
import copy
import datetime import datetime
import os import os
import time import time
from dataclasses import dataclass, field
from typing import List
from dotenv import load_dotenv import aiohttp
from aiohttp.web_exceptions import HTTPException
from bring_api import Bring from bring_api import Bring
from bring_api.exceptions import BringException from bring_api.exceptions import BringException
from dotenv import load_dotenv
load_dotenv() load_dotenv()
EXCEPTION_SLEEP_INTERVAL = 60 EXCEPTION_SLEEP_INTERVAL = 60
PLUGIN_SLEEP_INTERVAL = 60 * 15 # 15 minutes
@dataclass
class BringList:
"""Represents a Bring list"""
name: str = ""
uuid: str = ""
items: List[str] = field(default_factory=list)
def __eq__(self, other):
if isinstance(other, BringList):
return (
self.name == other.name
and self.uuid == other.uuid
and set(self.items) == set(other.items)
)
return False
class BringPlugin: class BringPlugin:
SLEEP_INTERVAL = 15 * 60 # 15 minutes """
Class syncing Bring shopping list with TRMNL.
The plugin currently supports only one shopping list.
"""
def __init__(self): def __init__(self):
self.email = os.getenv('EMAIL') self.email = os.getenv("EMAIL")
self.password = os.getenv('PASSWORD') self.password = os.getenv("PASSWORD")
self.webhook_url = os.getenv('WEBHOOK_URL') self.webhook_url = os.getenv("WEBHOOK_URL")
self.items = [] self.bring = None
self.existing_list = None
async def grabItems(self): async def grab_items(self, bring_list):
itemObjs = (await self.bring.get_list(self.list)).items.purchase """Grabs the items of the list using the list's uuid"""
items = [item.itemId for item in itemObjs] item_objs = (await self.bring.get_list(bring_list.uuid)).items.purchase
bring_list.items = [item.itemId for item in item_objs]
print(f"Successfully fetched items at {datetime.datetime.now().isoformat()}") print(f"Successfully fetched items at {datetime.datetime.now().isoformat()}")
print(f"Items = {items}") print(f"Items = {bring_list.items}")
return items
async def send_list_to_trmnl(self, session, bring_list):
async def sendItemsToTerminal(self, session, items): """Sends the list to TRMNL if it has changed"""
if set (self.items) == set(items): if self.existing_list == bring_list:
print(f"The items list hasn't changed since the last fetch.") print("The items list hasn't changed since the last fetch.")
print(f"Skipping sending updates to TRMNL.") print("Skipping sending updates to TRMNL.")
return return
self.items = items self.existing_list = bring_list
try: try:
await session.post( await session.post(
self.webhook_url, self.webhook_url,
json={'merge_variables': {'items': items}}, json={
headers={'Content-Type': 'application/json'}, "merge_variables": {
raise_for_status=True) "items": self.existing_list.items,
"list_name": self.existing_list.name,
}
},
headers={"Content-Type": "application/json"},
raise_for_status=True,
)
current_timestamp = datetime.datetime.now().isoformat() current_timestamp = datetime.datetime.now().isoformat()
print(f"Items sent successfully to TRMNL at {current_timestamp}") print(f"Items sent successfully to TRMNL at {current_timestamp}")
except Exception as e: except HTTPException as e:
print(f"Exception occurred during sending items to TRMNL: {e}") print(f"Exception occurred during sending items to TRMNL: {e}")
async def run(self): async def run(self):
"""Start the plugin"""
async with aiohttp.ClientSession() as session: async with aiohttp.ClientSession() as session:
self.bring = Bring(session, self.email, self.password) self.bring = Bring(session, self.email, self.password)
await self.bring.login() await self.bring.login()
while True: while True:
self.list = (await self.bring.load_lists()).lists[0].listUuid new_list = None
items = await self.grabItems() if self.existing_list:
await self.sendItemsToTerminal(session, items) new_list = copy.deepcopy(self.existing_list)
time.sleep(self.SLEEP_INTERVAL) else:
bring_api_list = (await self.bring.load_lists()).lists[0]
new_list = BringList(name=bring_api_list.name, uuid=bring_api_list.listUuid)
await self.grab_items(new_list)
await self.send_list_to_trmnl(session, new_list)
time.sleep(PLUGIN_SLEEP_INTERVAL)
if __name__ == "__main__": if __name__ == "__main__":
bring_plugin = BringPlugin() bring_plugin = BringPlugin()
loop = asyncio.new_event_loop() loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop) asyncio.set_event_loop(loop)
while True: while True:
try: try:
loop.run_until_complete(bring_plugin.run()) loop.run_until_complete(bring_plugin.run())
@ -72,7 +115,7 @@ if __name__ == "__main__":
print(f"Bring exception occured: {e}") print(f"Bring exception occured: {e}")
print(f"Sleeping for {EXCEPTION_SLEEP_INTERVAL} seconds.") print(f"Sleeping for {EXCEPTION_SLEEP_INTERVAL} seconds.")
time.sleep(EXCEPTION_SLEEP_INTERVAL) time.sleep(EXCEPTION_SLEEP_INTERVAL)
print(f"Retrying the service") print("Retrying the service")
except Exception as e: except Exception as e:
print(f"Unknown exception occured: {e}") print(f"Unknown exception occured: {e}")
raise raise

View file

@ -24,8 +24,7 @@
{% for item in items_to_display %} {% for item in items_to_display %}
{% assign number_of_items_displayed = number_of_items_displayed | plus: 1 %} {% assign number_of_items_displayed = number_of_items_displayed | plus: 1 %}
<div class="item"> <div class="item">
<div class="meta"> <div class="meta"></div>
</div>
<div class="content"> <div class="content">
<span class="title title--small">{{ item }}</span> <span class="title title--small">{{ item }}</span>
</div> </div>
@ -41,8 +40,5 @@
src="https://cdn.prod.website-files.com/5fbe6548a005d56f0dd39a2e/5fc24a65f7e1555200865e1b_bring-logo.svg" src="https://cdn.prod.website-files.com/5fbe6548a005d56f0dd39a2e/5fc24a65f7e1555200865e1b_bring-logo.svg"
> >
<span class="title">Bring!</span> <span class="title">Bring!</span>
<span class="instance">Home</span> <span class="instance">{{ list_name }}</span>
</div> </div>
<!-- Include the overflow.js script -->
<script src="https://usetrmnl.com/js/latest/plugins.js"></script>

View file

@ -1,49 +1,44 @@
<div class="layout"> <div class="layout">
<div class="columns"> <div class="columns">
{% assign number_of_items_per_column = 6 %} {% assign number_of_items_per_column = 6 %}
{% assign number_of_columns = 2 %} {% assign number_of_columns = 2 %}
{% assign total_count = items | size %} {% assign total_count = items | size %}
{% assign number_of_items_displayed = 0 %} {% assign number_of_items_displayed = 0 %}
{% assign var = number_of_columns | minus: 1 %} {% assign var = number_of_columns | minus: 1 %}
{% for i in (0..var) %} {% for i in (0..var) %}
{% if number_of_items_displayed >= total_count %} {% if number_of_items_displayed >= total_count %}
{% break %} {% break %}
{% endif %}
<div
class="column"
data-list-limit="true"
data-list-hidden-count="true"
data-list-max-height="170"
>
{% assign items_to_display_count = number_of_items_per_column %}
{% if i == var %}
{% assign items_to_display_count = total_count | minus: number_of_items_displayed %}
{% endif %} {% endif %}
<div {% assign items_to_display = items | slice: number_of_items_displayed, items_to_display_count %}
class="column" {% for item in items_to_display %}
data-list-limit="true" {% assign number_of_items_displayed = number_of_items_displayed | plus: 1 %}
data-list-hidden-count="true" <div class="item">
data-list-max-height="170" <div class="meta"></div>
> <div class="content">
{% assign items_to_display_count = number_of_items_per_column %} <span class="title title--small">{{ item }}</span>
{% if i == var %}
{% assign items_to_display_count = total_count | minus: number_of_items_displayed %}
{% endif %}
{% assign items_to_display = items | slice: number_of_items_displayed, items_to_display_count %}
{% for item in items_to_display %}
{% assign number_of_items_displayed = number_of_items_displayed | plus: 1 %}
<div class="item">
<div class="meta">
</div>
<div class="content">
<span class="title title--small">{{ item }}</span>
</div>
</div> </div>
{% endfor %} </div>
</div> {% endfor %}
{% endfor %} </div>
</div> {% endfor %}
</div> </div>
<div class="title_bar"> </div>
<img <div class="title_bar">
class="image" <img
src="https://cdn.prod.website-files.com/5fbe6548a005d56f0dd39a2e/5fc24a65f7e1555200865e1b_bring-logo.svg" class="image"
> src="https://cdn.prod.website-files.com/5fbe6548a005d56f0dd39a2e/5fc24a65f7e1555200865e1b_bring-logo.svg"
<span class="title">Bring!</span> >
<span class="instance">Home</span> <span class="title">Bring!</span>
</div> <span class="instance">{{ list_name }}</span>
</div>
<!-- Include the overflow.js script -->
<script src="https://usetrmnl.com/js/latest/plugins.js"></script>