map-dots-fetch/main.py

176 lines
6.7 KiB
Python
Raw Normal View History

2023-08-14 20:26:26 +01:00
### map-dots-fetch
### Connects to a map-dots instance and fetches images, saving them to the filesystem. Cross platform support is
### provided and only the Python standard library is used - it should run on any system with Python 3.x installed
### The script is designed to be run on a schedule using systemd-timers of cron. The choice is yours - of course
### you can also run it manually if you wish.
### A configuration file should be created at /etc/map-dots-fetch/conf.toml or ~/.config/map-dots-fetch/conf.toml for Linux
### or at \Users\{username}\map-dots-fetch.toml for Windows.
### If no configuration file can be found at these paths, the program directory will be checked.
### If both paths exist on Linux, the file in your home directory will take precedence
### Configurable Options (Example configuration):
"""
conf.toml
---------
[server]
# Include the scheme in the url, eg. "https://" or "http://"
url = ""
port = 443
[images]
# Image settings are arrays, this enables you to generate multiple images with
# different settings at the same time.
# Traccar Device ID
deviceId = [1]
# Output Image Size
size = [[1920,1080]]
# Valid values from from & to are: "now", "-hour", "-day", "-week", "-month", "-quarter"
from = ["-month"]
to = ["now"]
# Output Image Style
style = ["circles"]
format = "png"
[files]
destDir = "/var/wallpapers/map-dots"
"""
##### LICENSE #####
"""
Copyright 2023 Frederick Boniface (git.fjla.uk/fredboniface.co.uk)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
documentation files (the Software), to deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
"""
import os, sys, requests, datetime, tomllib
from pathlib import Path
pre_start = datetime.datetime.now().timestamp()
print("Finding configuration file")
user = os.environ.get('USERNAME', os.environ.get('USER'))
os_type = os.name
global_conf_path = "/etc/map-dots-fetch/conf.toml"
home_path = Path.home()
local_conf_path = f"{home_path}/.config/map-dots-fetch/conf.toml"
win_conf_path = f"{home_path}\\map-dots-fetch.toml"
if os.path.exists(local_conf_path) and os_type == "posix":
conf_path = local_conf_path
elif os.path.exists(global_conf_path) and os_type == "posix":
conf_path = global_conf_path
elif os.path.exists(win_conf_path) and os_type == "nt":
conf_path = win_conf_path
elif os.path.exists("conf.toml"):
conf_path = "conf.toml"
else:
if os_type == "posix":
print(f"Unable to find configuration file after searching '{global_conf_path}', '{local_conf_path}', and './conf.toml'")
elif os_type == "nt":
print(f"Unable to find configuration file after searching '{win_conf_path}' and this directory")
else:
print(f"System type: {os_type}, not supported.")
sys.exit(1)
print(f"Loading configuration file: {conf_path}")
with open(conf_path, 'rb') as conf:
conf_values = tomllib.load(conf)
request_url = f"{conf_values['server']['url']}:{conf_values['server']['port']}/traccar/"
# Define usable datetime objects
dateMap = {
'now': datetime.datetime.utcnow(),
'-hour': datetime.datetime.utcnow() - datetime.timedelta(hours=1),
'-day': datetime.datetime.utcnow() - datetime.timedelta(days=1),
'-week': datetime.datetime.utcnow() - datetime.timedelta(weeks=1),
'-month': datetime.datetime.utcnow() - datetime.timedelta(days=30), # Approximate 30 days
'-quarter': datetime.datetime.utcnow() - datetime.timedelta(days=90) # Approximate 90 days
}
print("Ensuring destination folders exist")
os.makedirs(conf_values['files']['destDir'], exist_ok=True)
for i in range(len(conf_values['images']['deviceId'])):
img_dev_id = conf_values['images']['deviceId'][i]
img_width, img_height = conf_values['images']['size'][i]
img_from = dateMap[conf_values['images']['from'][i]].strftime("%Y-%m-%dT%H:%M:%SZ")
img_to = dateMap[conf_values['images']['to'][i]].strftime("%Y-%m-%dT%H:%M:%SZ")
img_style = conf_values['images']['style'][i]
img_format = conf_values['images']['format']
print("Requesting image:")
print(f"ID: {img_dev_id}, Size: {img_width}x{img_height}, From/To: {img_from}, {img_to}, Style: {img_style}, Format: {img_format}")
params = {
"id": img_dev_id,
"width": img_width,
"height": img_height,
"from": img_from,
"to": img_to,
"format": img_format
}
pre_req_time = datetime.datetime.now().timestamp()
try:
res = requests.get(request_url, params=params, timeout=120)
except requests.Timeout:
print("HTTP request timed out after 2 minutes")
sys.exit(1)
except requests.RequestException as e:
print("Error with HTTP request: ", e)
sys.exit(1)
post_res_time = datetime.datetime.now().timestamp()
print(f"HTTP request completed in {post_res_time - pre_req_time} seconds")
if res.status_code != 200:
print(f"HTTP Response error: {res.status_code}")
sys.exit(1)
print("Ensuring image directory exists")
image_dir = os.path.join(conf_values['files']['destDir'], f"{i}")
os.makedirs(image_dir, exist_ok=True)
print("Deleting old image files")
for filename in os.listdir(image_dir):
file_path = os.path.join(image_dir, filename)
try:
if os.path.isfile(file_path):
os.unlink(file_path)
except Exception as e:
print("Error deleting old file: ", e)
print("Saving image")
image_filename = f"mapdot-{i}-{img_to}.png"
image_path = os.path.join(image_dir, image_filename)
try:
with open(image_path, "wb") as image_file:
image_file.write(res.content)
print(f"Image saved: {image_path}")
except Exception as e:
print(f"Unable to save image file: {e}")
pre_finish = datetime.datetime.now().timestamp()
print(f"map-dots-fetch completed in: {pre_finish - pre_start} seconds")