# DeckBro: a simple DeckText/HTML browser for T-DeckARD environment # Usage: from app.bro import DeckBro # Created by Luxferre in 2025-2026, released into public domain import re from deck.pager import print_paged from deck.input import input, input_multi from deck.menu import menu from deck.http import http_fetch, http_set_ua from deck.text import DeckText class DeckBro: def __init__(self, start_url=''): self.history = [] self.rendered_pages = [] self.history_pos = 0 # always refers to the current slot self.url = start_url self.doc = DeckText() if self.url: self.go(self.url) def render(self): pagenum = 1 pagetotal = len(self.doc.pages) self.rendered_pages = [] for page in self.doc.pages: outtext = f'{self.doc.title} ({pagenum}/{pagetotal})\n---\n' outtext += page['content'] if len(page['links']) > 0: linknum = 1 outtext += '\n--- Links ---\n' for l in page['links']: outtext += f'[{linknum}] {l[1]}: {l[0]}\n' linknum += 1 self.rendered_pages.append(outtext) pagenum += 1 return len(self.rendered_pages) def display(self): curpage = 1 totalpages = len(self.rendered_pages) menustring = 'g)o r)ef b)ack f)wd n)ext p)rev l)ink or pg#: ' do_new_display = True while True: if do_new_display and curpage > 0 and curpage <= totalpages: print_paged(self.rendered_pages[curpage - 1]) print(f'[{self.url}]') user_choice = input(menustring).strip() pgnum = None try: # page number input detection pgnum = int(user_choice) except: pass if pgnum is not None: if pgnum > 0 and pgnum <= totalpages: curpage = pgnum do_new_display = True else: print('Invalid page number!') do_new_display = False continue user_opt = '' try: user_opt = ' '.join(user_choice.split(' ')[1:]) except: pass if user_choice == '': user_choice = 'n' # go to the next page by default ch_letter = user_choice[0].lower() if ch_letter == 'q': break elif ch_letter == 'n': do_new_display = True curpage += 1 if curpage > totalpages: # wrap around curpage = 1 elif ch_letter == 'p': do_new_display = True curpage -= 1 if curpage < 1: # wrap around curpage = totalpages elif ch_letter == 'g': self.go(user_opt) break elif ch_letter == 'l': addr = None try: lnum = int(user_opt) addr = self.doc.pages[curpage - 1]['links'][lnum - 1][0] except: pass if addr is None: print('Invalid link number entered!') do_new_display = False else: self.go(addr) break elif ch_letter == 'r': self.refresh() break elif ch_letter == 'b': if self.back() is not None: break else: do_new_display = False elif ch_letter == 'f': if self.forward() is not None: break else: do_new_display = False def go(self, url=None, update_history=True): base_url = '' current_url = self.url match = re.search(r'^(https?://[^/]+)', current_url) if match: base_url = match.group(1) if url: new_url = url.strip() if current_url != '' and not new_url.lower().startswith('http'): if new_url.startswith('/'): new_url = base_url + new_url else: new_url = current_url + '/' + new_url self.url = re.sub(r'([^:])//+', r'\1/', new_url) status, pagetext = http_fetch(self.url) if status != 200: if pagetext == '': pagetext = f'Error {status}' else: pagetext = f'Error {status}: \n{pagetext}' self.doc.load(pagetext) if len(self.doc.pages) > 0 and update_history: self.history = self.history[0:self.history_pos+1] self.history.append(self.url) self.history_pos = len(self.history) - 1 self.render() self.display() def refresh(self): self.go(self.url, update_history=False) def back(self): if self.history_pos > 0: self.history_pos -= 1 new_url = self.history[self.history_pos] self.go(new_url, update_history=False) return new_url return None def forward(self): if self.history_pos < len(self.history) - 1: self.history_pos += 1 new_url = self.history[self.history_pos] self.go(new_url, update_history=False) return new_url return None # create and start a default DeckBro instance def bro(url=None): inst = DeckBro() inst.go(url)