Added (plain) text to display module
This commit is contained in:
		| @@ -6,4 +6,5 @@ from .inkycal_todoist import Todoist | ||||
| from .inkycal_image import Inkyimage | ||||
| from .inkycal_jokes import Jokes | ||||
| from .inkycal_stocks import Stocks | ||||
| from .inkycal_slideshow import Slideshow | ||||
| from .inkycal_slideshow import Slideshow | ||||
| from .inkycal_textfile_to_display import TextToDisplay | ||||
							
								
								
									
										117
									
								
								inkycal/modules/inkycal_textfile_to_display.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								inkycal/modules/inkycal_textfile_to_display.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,117 @@ | ||||
| #!python3 | ||||
| """ | ||||
| Textfile module for InkyCal Project | ||||
|  | ||||
| Reads data from a plain .txt file and renders it on the display. | ||||
| If the content is too long, it will be truncated from the back until it fits | ||||
|  | ||||
| Copyright by aceisace | ||||
| """ | ||||
| from inkycal.modules.template import inkycal_module | ||||
| from inkycal.custom import * | ||||
|  | ||||
| from urllib.request import urlopen | ||||
|  | ||||
| logger = logging.getLogger(__name__) | ||||
|  | ||||
|  | ||||
| class TextToDisplay(inkycal_module): | ||||
|     """TextToDisplay module | ||||
|     """ | ||||
|  | ||||
|     name = "Text module - Display text from a local file on the display" | ||||
|  | ||||
|     requires = { | ||||
|         "filepath": { | ||||
|             "label": "Please enter a filepath or URL pointing to a .txt file", | ||||
|         }, | ||||
|     } | ||||
|  | ||||
|     def __init__(self, config): | ||||
|         """Initialize inkycal_textfile_to_display module""" | ||||
|  | ||||
|         super().__init__(config) | ||||
|  | ||||
|         config = config['config'] | ||||
|  | ||||
|         # Check if all required parameters are present | ||||
|         for param in self.requires: | ||||
|             if param not in config: | ||||
|                 raise Exception(f'config is missing {param}') | ||||
|  | ||||
|         # required parameters | ||||
|         self.filepath = config["filepath"] | ||||
|  | ||||
|         self.make_request = True if self.filepath.startswith("https://") else False | ||||
|  | ||||
|  | ||||
|         # give an OK message | ||||
|         print(f'{__name__} loaded') | ||||
|  | ||||
|     def _validate(self): | ||||
|         """Validate module-specific parameters""" | ||||
|         # ensure we only use a single file | ||||
|         assert (self.filepath and len(self.filepath) == 1) | ||||
|  | ||||
|     def generate_image(self): | ||||
|         """Generate image for this module""" | ||||
|  | ||||
|         # Define new image size with respect to padding | ||||
|         im_width = int(self.width - (2 * self.padding_left)) | ||||
|         im_height = int(self.height - (2 * self.padding_top)) | ||||
|         im_size = im_width, im_height | ||||
|         logger.info(f'Image size: {im_size}') | ||||
|  | ||||
|         # Create an image for black pixels and one for coloured pixels | ||||
|         im_black = Image.new('RGB', size=im_size, color='white') | ||||
|         im_colour = Image.new('RGB', size=im_size, color='white') | ||||
|  | ||||
|         # Check if internet is available | ||||
|         if internet_available(): | ||||
|             logger.info('Connection test passed') | ||||
|         else: | ||||
|             raise NetworkNotReachableError | ||||
|  | ||||
|         # Set some parameters for formatting feeds | ||||
|         line_spacing = 1 | ||||
|         line_height = self.font.getsize('hg')[1] + line_spacing | ||||
|         line_width = im_width | ||||
|         max_lines = (im_height // (self.font.getsize('hg')[1] + line_spacing)) | ||||
|  | ||||
|         # Calculate padding from top so the lines look centralised | ||||
|         spacing_top = int(im_height % line_height / 2) | ||||
|  | ||||
|         # Calculate line_positions | ||||
|         line_positions = [ | ||||
|             (0, spacing_top + _ * line_height) for _ in range(max_lines)] | ||||
|  | ||||
|         if self.make_request: | ||||
|             logger.info("Detected http path, making request") | ||||
|             file_content = urlopen(self.filepath).read().decode('utf-8') | ||||
|         else: | ||||
|             # Create list containing all lines | ||||
|             with open(self.filepath, 'r') as file: | ||||
|                 file_content = file.read() | ||||
|  | ||||
|         fitted_content = text_wrap(file_content, font=self.font, max_width=im_width) | ||||
|  | ||||
|         # Trim down the list to the max number of lines | ||||
|         del fitted_content[max_lines:] | ||||
|  | ||||
|         # Write feeds on image | ||||
|         for index, line in enumerate(fitted_content): | ||||
|             write( | ||||
|                 im_black, | ||||
|                 line_positions[index], | ||||
|                 (line_width, line_height), | ||||
|                 line, | ||||
|                 font=self.font, | ||||
|                 alignment='left' | ||||
|             ) | ||||
|  | ||||
|         # return images | ||||
|         return im_black, im_colour | ||||
|  | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|     print(f'running {__name__} in standalone/debug mode') | ||||
							
								
								
									
										126
									
								
								inkycal/tests/test_inkycal_textfile_to_display.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								inkycal/tests/test_inkycal_textfile_to_display.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,126 @@ | ||||
| #!python3 | ||||
| import os | ||||
| import unittest | ||||
| from inkycal.modules import TextToDisplay as Module | ||||
| from helper_functions import * | ||||
|  | ||||
| environment = get_environment() | ||||
|  | ||||
| # Set to True to preview images. Only works on Raspberry Pi OS with Desktop | ||||
| use_preview = False | ||||
|  | ||||
| file_path = None | ||||
|  | ||||
| dummy_data = [ | ||||
|     'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', ' Donec feugiat facilisis neque vel blandit.', | ||||
|     'Integer viverra dolor risus.', ' Etiam neque tellus, sollicitudin at nisi a, mollis ornare enim.', | ||||
|     'Quisque sed ante eu leo dictum sagittis quis nec nisi.', | ||||
|     'Suspendisse id nulla dictum, sollicitudin urna id, iaculis elit.', | ||||
|     'Nulla luctus pellentesque diam, ac consequat urna molestie vitae.', | ||||
|     'Donec elementum turpis eget augue laoreet, nec maximus lacus malesuada.', '\n\nEtiam eu nunc mauris.', | ||||
|     'Nullam aliquam tristique leo, at dignissim turpis sodales vitae.', | ||||
|     'Aenean cursus laoreet neque, sit amet semper orci tincidunt et.', | ||||
|     'Proin orci urna, efficitur malesuada mattis at, pretium commodo odio.', | ||||
|     'Maecenas in ante id eros aliquam porttitor quis eget est.', | ||||
|     'Duis ex urna, porta nec semper nec, dignissim eu urna.', ' Quisque eleifend non magna at rutrum.', | ||||
|     '\nSed at eros blandit, tempor quam et, mollis ante.', ' Etiam fringilla euismod gravida.', | ||||
|     'Curabitur facilisis consectetur luctus.', | ||||
|     'Integer lectus augue, convallis a consequat id, sollicitudin eget lorem.', | ||||
|     'Curabitur tincidunt suscipit nibh quis mollis.', | ||||
|     'Fusce cursus, orci ut maximus fringilla, velit mauris dictum est, sed ultricies ante orci viverra erat.', | ||||
|     'Quisque pellentesque, mauris nec vulputate commodo, risus libero volutpat nibh, vel tristique mi neque id quam.', | ||||
|     '\nVivamus blandit, dolor ut interdum sagittis, arcu tortor finibus nibh, ornare convallis dui velit quis nunc.', | ||||
|     'Sed turpis justo, pellentesque eu risus scelerisque, vestibulum vulputate magna.', | ||||
|     'Vivamus tincidunt sollicitudin nisl, feugiat euismod nulla consequat ut.', | ||||
|     'Praesent bibendum, sapien sit amet aliquet posuere, tellus purus porta lectus, ut volutpat purus tellus tempus est.', | ||||
|     'Maecenas condimentum lobortis erat nec dignissim', ' Nulla molestie posuere est', | ||||
|     'Proin ultrices, nisl id luctus lacinia, augue ipsum pharetra leo, quis commodo augue dui varius urna.', | ||||
|     'Morbi ultrices turpis malesuada tellus fermentum vulputate.', | ||||
|     'Aliquam viverra nulla aliquam viverra gravida.', ' Pellentesque eu viverra massa.', | ||||
|     'Vestibulum id nisl vehicula, aliquet dui sed, venenatis eros.', | ||||
|     'Nunc iaculis, neque vitae euismod viverra, nisl mauris luctus velit, a aliquam turpis erat fringilla libero.', | ||||
|     'Ut ligula elit, lacinia convallis tempus interdum, finibus ut ex.', | ||||
|     'Nulla efficitur ac ligula sit amet dignissim.', ' Donec sed mi et justo venenatis faucibus.', | ||||
|     'Sed tincidunt nibh erat, in vestibulum purus consequat eget.', | ||||
|     '\nNulla iaculis volutpat orci id efficitur.', ' Vivamus vehicula sit amet augue tristique dignissim.', | ||||
|     'Praesent eget nulla est.', ' Integer nec diam fermentum, convallis metus lacinia, lobortis mauris.', | ||||
|     'Nulla venenatis metus fringilla, lacinia sem nec, pharetra sapien.', | ||||
|     'Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.', | ||||
|     'Duis facilisis sapien est, a elementum lorem maximus ut.' | ||||
| ] | ||||
|  | ||||
| tests = [ | ||||
|     { | ||||
|         "position": 1, | ||||
|         "name": "TextToFile", | ||||
|         "config": { | ||||
|             "size": [500, 100], | ||||
|             "filepath": file_path, | ||||
|             "padding_x": 10, | ||||
|             "padding_y": 10, | ||||
|             "fontsize": 12, | ||||
|             "language": "en" | ||||
|         } | ||||
|     }, | ||||
|     { | ||||
|         "position": 1, | ||||
|         "name": "TextToFile", | ||||
|         "config": { | ||||
|             "size": [500, 400], | ||||
|             "filepath": file_path, | ||||
|             "padding_x": 10, | ||||
|             "padding_y": 10, | ||||
|             "fontsize": 12, | ||||
|             "language": "en" | ||||
|         } | ||||
|     }, | ||||
| ] | ||||
|  | ||||
|  | ||||
| class TestTextToDisplay(unittest.TestCase): | ||||
|     def test_get_config(self): | ||||
|         print('getting data for web-ui...', end="") | ||||
|         Module.get_config() | ||||
|         print('OK') | ||||
|  | ||||
|     def test_generate_image(self): | ||||
|         delete_file_after_parse = False | ||||
|  | ||||
|         if not file_path: | ||||
|             delete_file_after_parse = True | ||||
|             print("Filepath does not exist. Creating dummy file") | ||||
|  | ||||
|             tmp_path = "tmp.txt" | ||||
|             with open(tmp_path, mode="w") as file: | ||||
|                 file.writelines(dummy_data) | ||||
|  | ||||
|             # update tests with new temp path | ||||
|             for test in tests: | ||||
|                 test["config"]["filepath"] = tmp_path | ||||
|  | ||||
|         else: | ||||
|             make_request = True if file_path.startswith("https://") else False | ||||
|             if not make_request and not os.path.exists(file_path): | ||||
|                 raise FileNotFoundError("Your text file could not be found") | ||||
|  | ||||
|         for test in tests: | ||||
|             print(f'test {tests.index(test) + 1} generating image..') | ||||
|             module = Module(test) | ||||
|             im_black, im_colour = module.generate_image() | ||||
|             print('OK') | ||||
|             if use_preview and environment == 'Raspberry': | ||||
|                 preview(merge(im_black, im_colour)) | ||||
|             im = merge(im_black, im_colour) | ||||
|             im.show() | ||||
|  | ||||
|         if delete_file_after_parse: | ||||
|             print("cleaning up temp file") | ||||
|             os.remove("tmp.txt") | ||||
|  | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|     logger = logging.getLogger() | ||||
|     logger.level = logging.DEBUG | ||||
|     logger.addHandler(logging.StreamHandler(sys.stdout)) | ||||
|  | ||||
|     unittest.main() | ||||
		Reference in New Issue
	
	Block a user