create browser class
This commit is contained in:
		
							parent
							
								
									e65d430aac
								
							
						
					
					
						commit
						e7dd7a1629
					
				
							
								
								
									
										227
									
								
								nex.py
									
									
									
									
									
								
							
							
						
						
									
										227
									
								
								nex.py
									
									
									
									
									
								
							| @ -12,47 +12,12 @@ logger.setLevel(logging.INFO) | |||||||
| logger.addHandler(logging.FileHandler('nex.log')) | logger.addHandler(logging.FileHandler('nex.log')) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class Session: | def parse_url(url: str) -> Tuple[str, str]: | ||||||
|     def __init__(self): |     clean_url = url.replace('nex://', '') | ||||||
|         self.history = [Page('home')] |     split_url = clean_url.split('/', 1) | ||||||
|         self.curr_page_idx = 0 |     if len(split_url) == 1: | ||||||
| 
 |         return clean_url, '' | ||||||
|     def back(self): |     return split_url[0], split_url[1] | ||||||
|         if self.curr_page_idx > 0: |  | ||||||
|             self.curr_page_idx -= 1 |  | ||||||
|         self.render() |  | ||||||
| 
 |  | ||||||
|     def forward(self): |  | ||||||
|         if self.curr_page_idx < len(self.history) - 1: |  | ||||||
|             self.curr_page_idx += 1 |  | ||||||
|         self.render() |  | ||||||
| 
 |  | ||||||
|     def load(self, url): |  | ||||||
|         self.curr_page_idx += 1 |  | ||||||
|         if self.curr_page_idx >= len(self.history): |  | ||||||
|             self.history.append(Page(url)) |  | ||||||
|         else: |  | ||||||
|             self.history[self.curr_page_idx] = Page(url) |  | ||||||
|         self.history[self.curr_page_idx].request() |  | ||||||
| 
 |  | ||||||
|     def render(self): |  | ||||||
|         return self.history[self.curr_page_idx].content |  | ||||||
| 
 |  | ||||||
|     def reload(self): |  | ||||||
|         self.history[self.curr_page_idx].request() |  | ||||||
| 
 |  | ||||||
|     @property |  | ||||||
|     def current_page(self): |  | ||||||
|         return self.history[self.curr_page_idx] |  | ||||||
| 
 |  | ||||||
|     def follow_link(self, link_index: int): |  | ||||||
|         logger.info(link_index) |  | ||||||
|         url = self.current_page.links[link_index] |  | ||||||
|         if url.startswith('nex://'): |  | ||||||
|             self.load(url) |  | ||||||
|         else: |  | ||||||
|             url = '/'.join([self.current_page.url.rstrip('/'), url]) |  | ||||||
|             self.load(url) |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class Page: | class Page: | ||||||
| @ -69,7 +34,7 @@ class Page: | |||||||
|                 sock.connect((self.host, PORT)) |                 sock.connect((self.host, PORT)) | ||||||
|             except ConnectionError as e: |             except ConnectionError as e: | ||||||
|                 logger.error(e) |                 logger.error(e) | ||||||
|                 self.content = f'Error connecting to {self.host}' |                 self.content = f'[error]Could not connect to {self.host}' | ||||||
|                 return |                 return | ||||||
|             selector = self.selector + '\r\n' |             selector = self.selector + '\r\n' | ||||||
|             sock.sendall(selector.encode('ascii')) |             sock.sendall(selector.encode('ascii')) | ||||||
| @ -83,12 +48,12 @@ class Page: | |||||||
|                 self.raw_content = buf.decode('ascii') |                 self.raw_content = buf.decode('ascii') | ||||||
|             except UnicodeDecodeError as e: |             except UnicodeDecodeError as e: | ||||||
|                 logger.error(e) |                 logger.error(e) | ||||||
|                 self.content = 'Content could not be decoded' |                 self.content = '[warning]Content could not be decoded' | ||||||
|                 return |                 return | ||||||
|             self.content = self.raw_content |             self.content = self.raw_content | ||||||
|             self._parse_links() |             self._parse_links() | ||||||
|             for i, l in enumerate(self.links): |             for i, l in enumerate(self.links): | ||||||
|                 self.content = re.sub(l, f'[bold cyan]\[{i}][/] {l}', |                 self.content = re.sub(l, f'[bold primary]\[{i}][/] {l}', | ||||||
|                                       self.content, 1) |                                       self.content, 1) | ||||||
| 
 | 
 | ||||||
|     @property |     @property | ||||||
| @ -98,103 +63,127 @@ class Page: | |||||||
|     def _parse_links(self): |     def _parse_links(self): | ||||||
|         pattern = re.compile(r'=>\s*([\w/:\.~-]*)\s*') |         pattern = re.compile(r'=>\s*([\w/:\.~-]*)\s*') | ||||||
|         self.links = pattern.findall(self.raw_content) |         self.links = pattern.findall(self.raw_content) | ||||||
|         # Find links |  | ||||||
|         # Determine if absolute or relative |  | ||||||
|         # Parse out relative directory navigation |  | ||||||
|         # Store parsed URLs in array |  | ||||||
|         # Add numbers to page content corresponding to array index |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def parse_url(url: str) -> Tuple[str, str]: | landing_page = Page('') | ||||||
|     clean_url = url.replace('nex://', '') | landing_page.raw_content = 'Welcome to PyNex' | ||||||
|     split_url = clean_url.split('/', 1) | landing_page.content = landing_page.raw_content | ||||||
|     if len(split_url) == 1: |  | ||||||
|         return clean_url, '' |  | ||||||
|     return split_url[0], split_url[1] |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class BrowserWindow(ptg.Window): | class Session: | ||||||
|  |     def __init__(self): | ||||||
|  |         self.pages = {'': landing_page} | ||||||
|  |         self.history = [''] | ||||||
|  |         self.curr_index = 0 | ||||||
| 
 | 
 | ||||||
|     overflow = ptg.Overflow.SCROLL |     @property | ||||||
|     vertical_align = ptg.VerticalAlignment.TOP |     def current_page(self): | ||||||
|  |         return self.pages[self.history[self.curr_index]] | ||||||
| 
 | 
 | ||||||
|     def __init__(self, session: Session): |     def prev(self): | ||||||
|  |         if self.curr_index > 0: | ||||||
|  |             self.curr_index -= 1 | ||||||
|  |         return self.current_page | ||||||
|  | 
 | ||||||
|  |     def next(self): | ||||||
|  |         if self.curr_index < len(self.history) - 1: | ||||||
|  |             self.curr_index += 1 | ||||||
|  |         return self.current_page | ||||||
|  | 
 | ||||||
|  |     def new_page(self, url): | ||||||
|  |         self.curr_index += 1 | ||||||
|  |         if self.curr_index >= len(self.history): | ||||||
|  |             self.history.append(url) | ||||||
|  |         else: | ||||||
|  |             self.history[self.curr_index] = url | ||||||
|  |         page = Page(url) | ||||||
|  |         page.request() | ||||||
|  |         self.pages[url] = page | ||||||
|  |         return self.current_page | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class Browser(ptg.WindowManager): | ||||||
|  |     def __init__(self, session=Session(), *args): | ||||||
|         super().__init__() |         super().__init__() | ||||||
|  |         self.layout = ptg.Layout() | ||||||
|         self.session = session |         self.session = session | ||||||
|         self.set_widgets([session.render()]) |  | ||||||
|          |          | ||||||
|     def update(self) -> None: |         self.page_container = ptg.Container(self.session.current_page.content) | ||||||
|         self.set_widgets([session.render()]) |         self.body = ptg.Window(self.page_container, | ||||||
|  |                                overflow=ptg.Overflow.SCROLL, | ||||||
|  |                                vertical_align=ptg.VerticalAlignment.TOP) | ||||||
|  |         self.footer = ptg.Window( | ||||||
|  |                 ptg.Splitter( | ||||||
|  |                     ptg.KeyboardButton("Back", self.back, bound='b'), | ||||||
|  |                     ptg.KeyboardButton("Forward", self.forward, bound='f'), | ||||||
|  |                     ptg.KeyboardButton("Reload", self.reload, bound='r'), | ||||||
|  |                     ptg.KeyboardButton("Quit", self.stop, bound='q') | ||||||
|  |                     ), | ||||||
|  |                 box="EMPTY", | ||||||
|  |                 is_persistant=True | ||||||
|  |                 ) | ||||||
| 
 | 
 | ||||||
|     def window_back(self, *args): |         self._create_layout() | ||||||
|         self.session.back() |         self._create_key_bindings() | ||||||
|         self.update() |         self.update() | ||||||
| 
 | 
 | ||||||
|     def window_forward(self, *args): |     def _create_key_bindings(self): | ||||||
|         self.session.forward() |         self.bind('j', lambda *_: self.body.scroll(5)) | ||||||
|  |         self.bind(ptg.keys.DOWN, lambda *_: self.body.scroll(5)) | ||||||
|  |         self.bind('k', lambda *_: self.body.scroll(-5)) | ||||||
|  |         self.bind(ptg.keys.UP, lambda *_: self.body.scroll(-5)) | ||||||
|  |         self.bind('q', lambda *_: self.stop()) | ||||||
|  | 
 | ||||||
|  |         for i in range(10): | ||||||
|  |             self.bind(f'{i}', lambda widget, key: self.follow_link(key)) | ||||||
|  | 
 | ||||||
|  |     def _create_layout(self): | ||||||
|  |         self.layout.add_slot("Body") | ||||||
|  |         self.layout.add_break() | ||||||
|  |         self.layout.add_slot("Footer", height=1) | ||||||
|  | 
 | ||||||
|  |         # self.add(self.header) | ||||||
|  |         self.add(self.body) | ||||||
|  |         self.add(self.footer) | ||||||
|  | 
 | ||||||
|  |     def update(self): | ||||||
|  |         self.page_container.set_widgets([self.session.current_page.content]) | ||||||
|  |         self.body.set_title(f'[bold tertiary]{self.session.current_page.title}', 1) | ||||||
|  | 
 | ||||||
|  |     def back(self, *args): | ||||||
|  |         self.session.prev() | ||||||
|         self.update() |         self.update() | ||||||
| 
 | 
 | ||||||
|     def window_reload(self, *args): |     def forward(self, *args): | ||||||
|         self.session.reload() |         self.session.next() | ||||||
|         self.update() |         self.update() | ||||||
| 
 | 
 | ||||||
|     def follow_link(self, key: str): |     def reload(self, *args): | ||||||
|  |         self.session.current_page.request() | ||||||
|  |         self.update() | ||||||
|  | 
 | ||||||
|  |     def go(self, url): | ||||||
|  |         self.session.new_page(url) | ||||||
|  |         self.update() | ||||||
|  | 
 | ||||||
|  |     def follow_link(self, key): | ||||||
|         index = int(key) |         index = int(key) | ||||||
|         self.session.follow_link(index) |         url = self.session.current_page.links[index] | ||||||
|  |         if url.startswith('nex://'): | ||||||
|  |             self.session.new_page(url) | ||||||
|  |         else: | ||||||
|  |             url = '/'.join([self.session.current_page.url.rstrip('/'), url]) | ||||||
|  |             self.session.new_page(url) | ||||||
|         self.update() |         self.update() | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def _define_layout() -> ptg.Layout: | def main(url=None): | ||||||
|     layout = ptg.Layout() |     with Browser() as browser: | ||||||
|     layout.add_slot("Header", height=1) |         if url is not None: | ||||||
|     layout.add_break() |             browser.go(url) | ||||||
|     layout.add_slot("Body") |  | ||||||
|     layout.add_break() |  | ||||||
|     layout.add_slot("Footer", height=1) |  | ||||||
|     return layout |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def _create_footer(browser: BrowserWindow, manager: ptg.WindowManager): |  | ||||||
| 
 |  | ||||||
|     return ptg.Window( |  | ||||||
|             ptg.Splitter( |  | ||||||
|                 ptg.KeyboardButton("Back", browser.window_back, bound='b'), |  | ||||||
|                 ptg.KeyboardButton("Forward", browser.window_forward, bound='f'), |  | ||||||
|                 ptg.KeyboardButton("Reload", browser.window_reload, bound='r'), |  | ||||||
|                 ptg.KeyboardButton("Quit", lambda *_: manager.stop(), bound='q') |  | ||||||
|                 ), |  | ||||||
|             box="EMPTY", |  | ||||||
|             is_persistant=True |  | ||||||
|             ) |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| if __name__ == '__main__': | if __name__ == '__main__': | ||||||
|     session = Session() |  | ||||||
|     if len(sys.argv) > 1: |     if len(sys.argv) > 1: | ||||||
|         url = sys.argv[1] |         url = sys.argv[1] | ||||||
|     if len(sys.argv) > 2 and sys.argv[2] == '--notui': |     main(url) | ||||||
|         url = sys.argv[1] |  | ||||||
|         session.load(url) |  | ||||||
|         print(session.render()) |  | ||||||
|         session.follow_link(0) |  | ||||||
|         print(session.render()) |  | ||||||
|         sys.exit(0) |  | ||||||
|     session.load(url) |  | ||||||
|     browser = BrowserWindow(session) |  | ||||||
|     with ptg.WindowManager() as manager: |  | ||||||
|         manager.layout = _define_layout() |  | ||||||
|         header = ptg.Window(f"[bold accent]{session.current_page.title}", |  | ||||||
|                             box="EMPTY", |  | ||||||
|                             is_persistant=True) |  | ||||||
|         manager.add(header) |  | ||||||
|         manager.add(browser, assign='body') |  | ||||||
|         manager.add(_create_footer(browser, manager), assign='footer') |  | ||||||
|         manager.bind('j', lambda *_: browser.scroll(5)) |  | ||||||
|         manager.bind(ptg.keys.DOWN, lambda *_: browser.scroll(5)) |  | ||||||
|         manager.bind('k', lambda *_: browser.scroll(-5)) |  | ||||||
|         manager.bind(ptg.keys.UP, lambda *_: browser.scroll(-5)) |  | ||||||
|         manager.bind('q', lambda *_: manager.stop()) |  | ||||||
| 
 |  | ||||||
|         for i in range(10): |  | ||||||
|             manager.bind(f'{i}', lambda widget, key: browser.follow_link(key)) |  | ||||||
|         logger.info(manager.bindings) |  | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user