add webshot module

This commit is contained in:
Ace 2023-11-21 20:16:10 +01:00
parent e093a13477
commit f0cb8528b8
6 changed files with 277 additions and 45 deletions

View File

@ -1,9 +1,9 @@
# Welcome to inkycal v2.0.3!
<p align="center">
<img src="https://raw.githubusercontent.com/aceisace/Inkycal/assets/Repo/logo.png" width="900">
<img src="https://raw.githubusercontent.com/aceisace/Inkycal/assets/Repo/logo.png" width="900" alt="aceinnolab logo">
</p>
<p align="center">
<img src="https://github.com/aceinnolab/Inkycal/blob/c1c274878ba81ddaee6186561e6ea892da54cd6a/Repo/inkycal-featured-gif.gif" width="900">
<img src="https://github.com/aceinnolab/Inkycal/blob/c1c274878ba81ddaee6186561e6ea892da54cd6a/Repo/inkycal-featured-gif.gif" width="900" alt="featured-image">
</p>
<p align="center">
@ -48,44 +48,44 @@ Before you can start, please ensure you have one of the supported displays and o
**❗Important note: e-paper displays cannot be simply connected to the Raspberry Pi, but require a driver board. The links below may or may not contain the required driver board. Please ensure you get the correct driver board for the display!**
| type | vendor | affiliate links to product |
| -- | -- | -- |
| 7.5" Inkycal (plug-and-play) | Author of Inkycal | [Buy on Tindie](https://www.tindie.com/products/aceisace4444/inkycal-build-v1/) Pre-configured version of Inkycal with custom frame and a web-ui. You do not need to buy anything extra. Includes Raspberry Pi Zero W, 7.5" e-paper, microSD card, driver board, custom packaging and 1m of cable. Comes pre-assembled for plug-and-play. |
| Inkycal frame | Author of Inkycal | coming soon (ultraslim frame with custom-made front and backcover inkl. ultraslim driver board). You will need a Raspberry Pi and a 7.5" e-paper display |
| `[serial]` 12.48" (1304×984px) display | waveshare / gooddisplay | <a target="_blank" href="https://www.amazon.de/gp/search?ie=UTF8&tag=aceisace-21&linkCode=ur2&linkId=7e08c6110a1a5b3511ead10db2fd909a&camp=1638&creative=6742&index=computers&keywords=Waveshare 12.48 Inch E-Paper">Waveshare 12.48 Inch E-Paper</a>
| `[serial]` 7.5" (640x384px) -> v1 display | waveshare / gooddisplay | <a target="_blank" href="https://www.amazon.de/gp/search?ie=UTF8&tag=aceisace-21&linkCode=ur2&linkId=1bf1a6338786c0a4e7b877335afa0683&camp=1638&creative=6742&index=computers&keywords=Waveshare 7.5 Inch E-Paper">Waveshare 7.5 Inch E-Paper</a> |
| `[serial]` 7.5" (800x400px) -> v2 display| waveshare / gooddisplay | <a target="_blank" href="https://www.amazon.de/gp/search?ie=UTF8&tag=aceisace-21&linkCode=ur2&linkId=1bf1a6338786c0a4e7b877335afa0683&camp=1638&creative=6742&index=computers&keywords=Waveshare 7.5 Inch E-Paper">Waveshare 7.5 Inch E-Paper</a> |
| `[serial]` 7.5" (880x528px) -> v3 display | waveshare / gooddisplay | <a target="_blank" href="https://www.amazon.de/gp/search?ie=UTF8&tag=aceisace-21&linkCode=ur2&linkId=1bf1a6338786c0a4e7b877335afa0683&camp=1638&creative=6742&index=computers&keywords=Waveshare 7.5 Inch E-Paper">Waveshare 7.5 Inch E-Paper</a> |
| `[serial]` 5.83" (400x300px) display | waveshare / gooddisplay | <a target="_blank" href="https://www.amazon.de/gp/search?ie=UTF8&tag=aceisace-21&linkCode=ur2&linkId=a4239753343f5fbbdb8f5be2f6b5e2b1&camp=1638&creative=6742&index=computers&keywords=Waveshare 5.83 Inch E-Paper">Waveshare 5.83 Inch E-Paper</a> |
| `[serial]` 4.2" (400x300px)display | waveshare / gooddisplay | <a target="_blank" href="https://www.amazon.de/gp/search?ie=UTF8&tag=aceisace-21&linkCode=ur2&linkId=7575de79f1728ab9f2bfb6a46d2238ee&camp=1638&creative=6742&index=computers&keywords=Waveshare 4.2 Inch E-Paper">Waveshare 4.2 Inch E-Paper</a> |
| `[parallel]` 10.3" (1872×1404px) display | waveshare / gooddisplay | <a target="_blank" href="https://www.amazon.de/gp/search?ie=UTF8&tag=aceisace-21&linkCode=ur2&linkId=b453e16c373b0d86e4828b22edecc206&camp=1638&creative=6742&index=computers&keywords=Waveshare 10.3 Inch E-Paper">Waveshare 10.3 Inch E-Paper</a> |
| `[parallel]` 9.7" (1200×825px) display | waveshare / gooddisplay | <a target="_blank" href="https://www.amazon.de/gp/search?ie=UTF8&tag=aceisace-21&linkCode=ur2&linkId=eef2be91cc3f850943109276a63a7162&camp=1638&creative=6742&index=computers&keywords=Waveshare 9.7 Inch E-Paper">Waveshare 9.7 Inch E-Paper</a> |
| `[parallel]` 7.8" (1872×1404px) display | waveshare / gooddisplay | <a target="_blank" href="https://www.amazon.de/gp/search?ie=UTF8&tag=aceisace-21&linkCode=ur2&linkId=f1863f9686b0eeeb04ce147791ba3789&camp=1638&creative=6742&index=computers&keywords=Waveshare 7.8 Inch E-Paper">Waveshare 7.8" E-Paper</a> |
| Raspberry Pi Zero W | Raspberry Pi | <a target="_blank" href="https://www.amazon.de/gp/search?ie=UTF8&tag=aceisace-21&linkCode=ur2&linkId=8f9c223197e1ab91b0372b1fe56ed508&camp=1638&creative=6742&index=computers&keywords=Raspberry Pi Zero W">Raspberry Pi Zero W</a> |
| MicroSD card | Sandisk | <a target="_blank" href="https://www.amazon.de/gp/search?ie=UTF8&tag=aceisace-21&linkCode=ur2&linkId=530a2b371c40bfeca48e875fb735a4a1&camp=1638&creative=6742&index=computers&keywords=Sandisk microSD 16GB U1 A1">MicroSD card (8GB)</a> |
| type | vendor | affiliate links to product |
|-------------------------------------------|-------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 7.5" Inkycal (plug-and-play) | Author of Inkycal |  [Buy on Tindie](https://www.tindie.com/products/aceisace4444/inkycal-build-v1/) Pre-configured version of Inkycal with custom frame and a web-ui. You do not need to buy anything extra. Includes Raspberry Pi Zero W, 7.5" e-paper, microSD card, driver board, custom packaging and 1m of cable. Comes pre-assembled for plug-and-play. |
| Inkycal frame | Author of Inkycal | coming soon (ultraslim frame with custom-made front and backcover inkl. ultraslim driver board). You will need a Raspberry Pi and a 7.5" e-paper display |
| `[serial]` 12.48" (1304×984px) display | waveshare / gooddisplay |  <a target="_blank" href="https://www.amazon.de/gp/search?ie=UTF8&tag=aceisace-21&linkCode=ur2&linkId=7e08c6110a1a5b3511ead10db2fd909a&camp=1638&creative=6742&index=computers&keywords=Waveshare 12.48 Inch E-Paper">Waveshare 12.48 Inch E-Paper</a> |
| `[serial]` 7.5" (640x384px) -> v1 display | waveshare / gooddisplay | <a target="_blank" href="https://www.amazon.de/gp/search?ie=UTF8&tag=aceisace-21&linkCode=ur2&linkId=1bf1a6338786c0a4e7b877335afa0683&camp=1638&creative=6742&index=computers&keywords=Waveshare 7.5 Inch E-Paper">Waveshare 7.5 Inch E-Paper</a> |
| `[serial]` 7.5" (800x400px) -> v2 display | waveshare / gooddisplay | <a target="_blank" href="https://www.amazon.de/gp/search?ie=UTF8&tag=aceisace-21&linkCode=ur2&linkId=1bf1a6338786c0a4e7b877335afa0683&camp=1638&creative=6742&index=computers&keywords=Waveshare 7.5 Inch E-Paper">Waveshare 7.5 Inch E-Paper</a> |
| `[serial]` 7.5" (880x528px) -> v3 display | waveshare / gooddisplay | <a target="_blank" href="https://www.amazon.de/gp/search?ie=UTF8&tag=aceisace-21&linkCode=ur2&linkId=1bf1a6338786c0a4e7b877335afa0683&camp=1638&creative=6742&index=computers&keywords=Waveshare 7.5 Inch E-Paper">Waveshare 7.5 Inch E-Paper</a> |
| `[serial]` 5.83" (400x300px) display | waveshare / gooddisplay | <a target="_blank" href="https://www.amazon.de/gp/search?ie=UTF8&tag=aceisace-21&linkCode=ur2&linkId=a4239753343f5fbbdb8f5be2f6b5e2b1&camp=1638&creative=6742&index=computers&keywords=Waveshare 5.83 Inch E-Paper">Waveshare 5.83 Inch E-Paper</a> |
| `[serial]` 4.2" (400x300px)display | waveshare / gooddisplay | <a target="_blank" href="https://www.amazon.de/gp/search?ie=UTF8&tag=aceisace-21&linkCode=ur2&linkId=7575de79f1728ab9f2bfb6a46d2238ee&camp=1638&creative=6742&index=computers&keywords=Waveshare 4.2 Inch E-Paper">Waveshare 4.2 Inch E-Paper</a> |
| `[parallel]` 10.3" (1872×1404px) display | waveshare / gooddisplay |  <a target="_blank" href="https://www.amazon.de/gp/search?ie=UTF8&tag=aceisace-21&linkCode=ur2&linkId=b453e16c373b0d86e4828b22edecc206&camp=1638&creative=6742&index=computers&keywords=Waveshare 10.3 Inch E-Paper">Waveshare 10.3 Inch E-Paper</a> |
| `[parallel]` 9.7" (1200×825px) display | waveshare / gooddisplay | <a target="_blank" href="https://www.amazon.de/gp/search?ie=UTF8&tag=aceisace-21&linkCode=ur2&linkId=eef2be91cc3f850943109276a63a7162&camp=1638&creative=6742&index=computers&keywords=Waveshare 9.7 Inch E-Paper">Waveshare 9.7 Inch E-Paper</a> |
| `[parallel]` 7.8" (1872×1404px) display | waveshare / gooddisplay |  <a target="_blank" href="https://www.amazon.de/gp/search?ie=UTF8&tag=aceisace-21&linkCode=ur2&linkId=f1863f9686b0eeeb04ce147791ba3789&camp=1638&creative=6742&index=computers&keywords=Waveshare 7.8 Inch E-Paper">Waveshare 7.8" E-Paper</a> |
| Raspberry Pi Zero W | Raspberry Pi |  <a target="_blank" href="https://www.amazon.de/gp/search?ie=UTF8&tag=aceisace-21&linkCode=ur2&linkId=8f9c223197e1ab91b0372b1fe56ed508&camp=1638&creative=6742&index=computers&keywords=Raspberry Pi Zero W">Raspberry Pi Zero W</a> |
| MicroSD card | Sandisk |  <a target="_blank" href="https://www.amazon.de/gp/search?ie=UTF8&tag=aceisace-21&linkCode=ur2&linkId=530a2b371c40bfeca48e875fb735a4a1&camp=1638&creative=6742&index=computers&keywords=Sandisk microSD 16GB U1 A1">MicroSD card (8GB)</a> |
## Configuring the Raspberry Pi
1. Flash Raspberry Pi OS on your microSD card (min. 4GB) with [Raspberry Pi Imager](https://rptl.io/imager). Use the following settings:
Flash Raspberry Pi OS on your microSD card (min. 4GB) with [Raspberry Pi Imager](https://rptl.io/imager). Use the following settings:
| option | value |
| :-- | :--: |
| hostname | inkycal |
| enable ssh | yes |
| set username and password | yes |
| username | a username you like |
| password | a password you can remember |
| set Wi-Fi | yes |
| Wi-Fi SSID | your Wi-Fi name |
| Wi-Fi password | your Wi-Fi password |
| option |  value |
|:---------------------------|:----------------------------:|
|  hostname |  inkycal |
|  enable ssh |  yes |
|  set username and password |  yes |
|  username |  a username you like |
|  password |  a password you can remember |
|  set Wi-Fi |  yes |
|  Wi-Fi SSID |  your Wi-Fi name |
|  Wi-Fi password |  your Wi-Fi password |
2. Create and download `settings.json` file for Inkycal from the [WEB-UI](https://aceisace.eu.pythonanywhere.com/inkycal-config-v2-0-0). Add the modules you want with the add module button.
3. Copy the `settings.json` to the flashed microSD card in the `/boot` folder of microSD card. On Windows, this is the only visible directory on the SD card. On Linux, copy these files to `/boot` of the microSD card.
4. Eject the microSD card from your computer now, insert it in the Raspberry Pi and power the Raspberry Pi.
5. Once the green LED has stopped blinking after ~3 minutes, you can connect to your Raspberry Pi via SSH using a SSH Client. We suggest [Termius](https://termius.com/download/windows)
1. Create and download `settings.json` file for Inkycal from the [WEB-UI](https://aceisace.eu.pythonanywhere.com/inkycal-config-v2-0-0). Add the modules you want with the add module button.
2. Copy the `settings.json` to the flashed microSD card in the `/boot` folder of microSD card. On Windows, this is the only visible directory on the SD card. On Linux, copy these files to `/boot` of the microSD card.
3. Eject the microSD card from your computer now, insert it in the Raspberry Pi and power the Raspberry Pi.
4. Once the green LED has stopped blinking after ~3 minutes, you can connect to your Raspberry Pi via SSH using a SSH Client. We suggest [Termius](https://termius.com/download/windows)
on your smartphone. Use the address: `inkycal.local` with the username and password you set earlier. For more detailed instructions, check out the page from the [Raspberry Pi website](https://www.raspberrypi.org/documentation/remote-access/ssh/)
6. After connecting via SSH, run the following commands, line by line:
5. After connecting via SSH, run the following commands, line by line:
```bash
sudo raspi-config --expand-rootfs
sudo sed -i s/#dtparam=spi=on/dtparam=spi=on/ /boot/config.txt
@ -118,9 +118,9 @@ These commands expand the filesystem, enable SPI and set up the correct timezone
Run the following steps to install Inkycal. Do **not** use sudo for this, except where explicitly specified.
```bash
# the next line is for the Raspberry Pi only
sudo apt-get install zlib1g libjpeg-dev libatlas-base-dev rustc libopenjp2-7 python3-dev scons libssl-dev python3-venv python3-pip git libfreetype6-dev
sudo apt-get install zlib1g libjpeg-dev libatlas-base-dev rustc libopenjp2-7 python3-dev scons libssl-dev python3-venv python3-pip git libfreetype6-dev wkhtmltopdf
cd $HOME
git clone --branch main --single-branch https://github.com/aceisace/Inkycal
git clone --branch main --single-branch https://github.com/aceinnolab/Inkycal
cd Inkycal
python3 -m venv venv
source venv/bin/activate

View File

@ -1,5 +1,3 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
"""
Inkycal custom-functions for ease-of-use
@ -11,7 +9,7 @@ import time
import traceback
import requests
from PIL import Image, ImageDraw, ImageFont
from PIL import ImageFont
logs = logging.getLogger(__name__)
logs.setLevel(level=logging.INFO)
@ -279,6 +277,7 @@ def internet_available():
from PIL import Image, ImageDraw
def draw_dotted_line(draw, start, end, colour, thickness):
"""Draws a dotted line between start and end points using dots."""
delta_x = end[0] - start[0]
@ -292,7 +291,8 @@ def draw_dotted_line(draw, start, end, colour, thickness):
# Drawing a circle at each dot position to create a dotted effect
draw.ellipse([(dot_position[0] - thickness, dot_position[1] - thickness),
(dot_position[0] + thickness, dot_position[1] + thickness)],
fill=colour)
fill=colour)
def draw_dashed_line(draw, start, end, colour, thickness):
"""Draws a dashed line between start and end points."""
@ -309,6 +309,7 @@ def draw_dashed_line(draw, start, end, colour, thickness):
segment_start[1] + (step_size * delta_y / distance))
draw.line((segment_start, segment_end), fill=colour, width=thickness)
def draw_border(image, xy, size, radius=5, thickness=1, shrinkage=(0.1, 0.1), style='solid'):
"""
Draws a border at given coordinates with specified styles (solid, dotted, dashed).

View File

@ -8,3 +8,4 @@ from .inkycal_jokes import Jokes
from .inkycal_stocks import Stocks
from .inkycal_slideshow import Slideshow
from .inkycal_textfile_to_display import TextToDisplay
from .inkycal_webshot import Webshot

View File

@ -0,0 +1,164 @@
"""
Webshot module for Inkycal
by https://github.com/worstface
"""
from htmlwebshot import WebShot
from inkycal.custom import *
from inkycal.modules.inky_image import Inkyimage as Images
from inkycal.modules.template import inkycal_module
from tests import Config
logger = logging.getLogger(__name__)
class Webshot(inkycal_module):
name = "Webshot - Displays screenshots of webpages"
# required parameters
requires = {
"url": {
"label": "Please enter the url",
},
"palette": {
"label": "Which color palette should be used for the webshots?",
"options": ["bw", "bwr", "bwy"]
}
}
optional = {
"crop_x": {
"label": "Please enter the crop x-position",
},
"crop_y": {
"label": "Please enter the crop y-position",
},
"crop_w": {
"label": "Please enter the crop width",
},
"crop_h": {
"label": "Please enter the crop height",
}
}
def __init__(self, config):
super().__init__(config)
config = config['config']
self.url = config['url']
self.palette = config['palette']
if "crop_h" in config and isinstance(config["crop_h"], str):
self.crop_h = int(config["crop_h"])
else:
self.crop_h = 2000
if "crop_w" in config and isinstance(config["crop_w"], str):
self.crop_w = int(config["crop_w"])
else:
self.crop_w = 2000
if "crop_x" in config and isinstance(config["crop_x"], str):
self.crop_x = int(config["crop_x"])
else:
self.crop_x = 0
if "crop_y" in config and isinstance(config["crop_y"], str):
self.crop_y = int(config["crop_y"])
else:
self.crop_y = 0
# give an OK message
print(f'Inkycal webshot loaded')
def generate_image(self):
"""Generate image for this module"""
# Create tmp path
tmpFolder = Config.TEMP_PATH
if not os.path.exists(tmpFolder):
print(f"Creating tmp directory {tmpFolder}")
os.mkdir(tmpFolder)
# 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('image size: {} x {} px'.format(im_width, im_height))
# Create an image for black pixels and one for coloured pixels (required)
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 Exception('Network could not be reached :/')
logger.info(
f'preparing webshot from {self.url}... cropH{self.crop_h} cropW{self.crop_w} cropX{self.crop_x} cropY{self.crop_y}')
shot = WebShot()
shot.params = {
"--crop-x": self.crop_x,
"--crop-y": self.crop_y,
"--crop-w": self.crop_w,
"--crop-h": self.crop_h,
}
logger.info(f'getting webshot from {self.url}...')
try:
shot.create_pic(url=self.url, output=f"{tmpFolder}/webshot.png")
except:
print(traceback.format_exc())
print("If you have not already installed wkhtmltopdf, please use: sudo apt-get install wkhtmltopdf. See here for more details: https://github.com/1Danish-00/htmlwebshot/")
raise Exception('Could not get webshot :/')
logger.info(f'got webshot...')
webshotSpaceBlack = Image.new('RGBA', (im_width, im_height), (255, 255, 255, 255))
webshotSpaceColour = Image.new('RGBA', (im_width, im_height), (255, 255, 255, 255))
im = Images()
im.load(f'{tmpFolder}/webshot.png')
im.remove_alpha()
imageAspectRatio = im_width / im_height
webshotAspectRatio = im.image.width / im.image.height
if webshotAspectRatio > imageAspectRatio:
imageScale = im_width / im.image.width
else:
imageScale = im_height / im.image.height
webshotHeight = int(im.image.height * imageScale)
im.resize(width=int(im.image.width * imageScale), height=webshotHeight)
im_webshot_black, im_webshot_colour = im.to_palette(self.palette)
webshotCenterPosY = int((im_height / 2) - (im.image.height / 2))
centerPosX = int((im_width / 2) - (im.image.width / 2))
webshotSpaceBlack.paste(im_webshot_black, (centerPosX, webshotCenterPosY))
im_black.paste(webshotSpaceBlack)
webshotSpaceColour.paste(im_webshot_colour, (centerPosX, webshotCenterPosY))
im_colour.paste(webshotSpaceColour)
im.clear()
logger.info(f'added webshot image')
# Save image of black and colour channel in image-folder
return im_black, im_colour

View File

@ -1,12 +1,12 @@
arrow==1.3.0
certifi==2023.7.22
certifi==2023.11.17
cycler==0.12.1
feedparser==6.0.10
fonttools==4.44.0
fonttools==4.45.0
icalendar==5.0.11
kiwisolver==1.4.5
lxml==4.9.3
matplotlib==3.8.1
matplotlib==3.8.2
numpy==1.24.4
packaging==23.2
Pillow==10.1.0
@ -14,14 +14,15 @@ pyparsing==3.1.1
PySocks==1.7.1
python-dateutil==2.8.2
pytz==2023.3.post1
recurring-ical-events==2.1.0
recurring-ical-events==2.1.1
requests==2.31.0
sgmllib3k==1.0.0
six==1.16.0
todoist-api-python==2.1.3
typing_extensions==4.8.0
urllib3==2.0.7
urllib3==2.1.0
python-dotenv==1.0.0
setuptools==68.2.2
setuptools==69.0.1
html2text==2020.1.16
yfinance==0.2.32
htmlwebshot~=0.1.2

65
tests/test_inkycal_webshot.py Executable file
View File

@ -0,0 +1,65 @@
"""
Test Inkycal Webshot Module
"""
import logging
import unittest
from inkycal.modules import Webshot
logger = logging.getLogger(__name__)
logging.basicConfig(level=logging.DEBUG)
tests = [
{
"position": 1,
"name": "Webshot",
"config": {
"size": [400, 100],
"url": "https://google.com",
"palette": "bwr",
"padding_x": 10, "padding_y": 10, "fontsize": 12, "language": "en"
}
},
{
"position": 1,
"name": "Webshot",
"config": {
"size": [400, 200],
"url": "https://google.com",
"palette": "bwy",
"padding_x": 10, "padding_y": 10, "fontsize": 12, "language": "en"
}
},
{
"position": 1,
"name": "Webshot",
"config": {
"size": [400, 300],
"url": "https://google.com",
"palette": "bw",
"padding_x": 10, "padding_y": 10, "fontsize": 12, "language": "en"
}
},
{
"position": 1,
"name": "Webshot",
"config": {
"size": [400, 400],
"url": "https://google.com",
"palette": "bwr",
"padding_x": 10, "padding_y": 10, "fontsize": 12, "language": "en"
}
}
]
class TestWebshot(unittest.TestCase):
def test_generate_image(self):
for test in tests:
logger.info(f'test {tests.index(test) + 1} generating image..')
module = Webshot(test)
module.generate_image()
logger.info('OK')