yavdr-ansible/roles/kodi/templates/set-kodi-display.j2

118 lines
4.0 KiB
Django/Jinja

#!/usr/bin/env python3
"""
{{ ansible_managed }}
This Script changes the monitor in KODI's guisettings.xml to the wanted output
according to the DISPLAY environment variable. It works with KODI 18 (not KODI 17!).
In order to change the display we need to modify the settings/videoscreen nodes.
Basic algorithm:
- get the current videoscreen.monitor
- check if it needs to be changed
- create a backup of the videoscreen nodes in /var/lib/vdr/.kodi/.display_cache/{CONNETOR}-videoscreen.xml
- check if there is an existing backup for the new CONNECTOR
- parse the backup of the videoscreen nodes
- replace the videoscreen nodes with the backup data
"""
import copy
import os
import sys
import subprocess
from lxml import etree as ET
GUISETTINGS = '/var/lib/vdr/.kodi/userdata/guisettings.xml'
CACHE_DIR = '/var/lib/vdr/.kodi/.display_cache'
VIDEOSCREEN_TEMPLATE = """<settings version="2">
<setting id="videoscreen.monitor">{}</setting>
</settings>"""
def create_cache_dir():
try:
os.makedirs(CACHE_DIR, exist_ok=True)
except PermissionError:
sys.exit(f"Error: insufficient permissions to create cachedir {CACHE_DIR}")
except Exception as e:
sys.exit(f"Unexpected Error when trying to create {CACHE_DIR}:", e)
def get_output_name():
"""
get display name from xrandr output for given DISPLAY environment variable
"""
try:
xrandr_output = [
l for l in subprocess.check_output(
["xrandr"],
env={"DISPLAY": os.environ["DISPLAY"]}
).decode("utf-8").splitlines()
]
return next(l.split()[0] for l in xrandr_output if " connected " in l)
except Exception as e:
sys.exit("could not determine output name", e)
def parse_template(template_path, template, output=""):
"""read videoscreen settings from backup or create a stub file"""
try:
xml_tree = ET.parse(template_path)
except OSError:
print(f"{template_path} not found, creating stub file", file=sys.stderr)
xml_template = ET.fromstring(template.format(output))
xml_tree = ET.ElementTree(xml_template)
finally:
xml_tree.write(template_path)
return xml_tree
def main(output):
guisettings = parse_template(GUISETTINGS, VIDEOSCREEN_TEMPLATE, "Default")
# parse guisettings Etree for display name an backup videoscreen data
root = guisettings.getroot()
old_output = root.find("./setting[@id='videoscreen.monitor']").text
if old_output == output:
print("no changes necessary, exiting", file=sys.stderr)
sys.exit()
# create a minimal guisettings etree
xml_path = os.path.join(CACHE_DIR, f'{old_output}-videoscreen.xml')
base_tree = ET.fromstring('<settings version="2"></settings>')
xml_tree = ET.ElementTree(base_tree)
backup_root = xml_tree.getroot()
# copy videoscreen elements to backup etree
videoscreen_elements = root.xpath(
"./setting[starts-with(@id, 'videoscreen.')]")
for element in videoscreen_elements:
backup_root.append(copy.deepcopy(element))
element.getparent().remove(element)
xml_tree.write(xml_path)
print(f"written backup for {old_output} to {xml_path}", file=sys.stderr)
# change videoscreen node to content of backup file
xml_path = os.path.join(CACHE_DIR, f'{output}-videoscreen.xml')
videodir_xml = parse_template(xml_path, VIDEOSCREEN_TEMPLATE, output)
videodir_root = videodir_xml.getroot()
videoscreen = videodir_root.find("./setting[@id='videoscreen.monitor']")
# copy videoscreen.* elements from Backup
videoscreen_elements = videodir_root.xpath(
"./setting[starts-with(@id, 'videoscreen.')]")
for element in videoscreen_elements:
new_element = copy.deepcopy(element)
root.append(new_element)
guisettings.write(GUISETTINGS)
if __name__ == '__main__':
create_cache_dir()
output = get_output_name()
try:
main(output)
except Exception as e:
print("Could not change videoscreen.* settings:", str(e), file=sys.stderr)