Last active
August 26, 2019 08:56
-
-
Save seahawk1986/6e964973c9e0bac1bc40ab1b915362f6 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
""" | |
*** ANSIBLE MANAGED FILE *** | |
template: /home/alexander/yavdr-ansible/roles/kodi/templates/set-kodi-display.j2 | |
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 logging | |
import os | |
import sys | |
import subprocess | |
import traceback | |
from lxml import etree as ET | |
logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.DEBUG) | |
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: | |
logging.exception(f"Unexpected Error when trying to create {CACHE_DIR}:") | |
sys.exit(1) | |
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: | |
logging.exception("could not determine output name") | |
sys.exit("output name unknown, exiting early") | |
def parse_template(template_path, template, output=""): | |
"""read videoscreen settings from backup or create a stub file""" | |
def xml_tree_from_template(template, output): | |
xml_template = ET.fromstring(template.format(output)) | |
xml_tree = ET.ElementTree(xml_template) | |
return xml_tree | |
try: | |
xml_tree = ET.parse(template_path) | |
except OSError: | |
logging.debug(f"{template_path} not found, creating stub file") | |
xml_tree = xml_tree_from_template(template, output) | |
except ET.XMLSyntaxError as e: | |
if e.msg.startswith('Document is empty'): | |
logging.info(f"{template_path} is empty, creating stub file") | |
xml_tree = xml_tree_from_template(template, output) | |
else: | |
sys.exit(f"Could not parse {template_path}, please fix file or remove it") | |
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: | |
logging.debug("no changes necessary, exiting") | |
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) | |
logging.debug(f"written backup for {old_output} to {xml_path}") | |
# 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: | |
logging.exception("Could not change videoscreen.* settings") | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment