Adapt set-kodi-display to KODI 18 final
This commit is contained in:
parent
65e2ac1e5f
commit
c0dc185952
99
Manual.org
99
Manual.org
@ -6028,104 +6028,7 @@ This systemd unit for the user session starts (and stops) kodi.
|
|||||||
#+INCLUDE: "roles/kodi/templates/kodi.service.j2" src conf
|
#+INCLUDE: "roles/kodi/templates/kodi.service.j2" src conf
|
||||||
**** set-kodi-diplay
|
**** set-kodi-diplay
|
||||||
This is a version-dependent script to force KODI to use the display set by the environment variable ~DISPLAY~. The following Version is intended for KODI 18.
|
This is a version-dependent script to force KODI to use the display set by the environment variable ~DISPLAY~. The following Version is intended for KODI 18.
|
||||||
#+BEGIN_SRC jinja2 :tangle roles/kodi/templates/set-kodi-display.j2 :padline no
|
#+INCLUDE: "roles/kodi/templates/set-kodi-display.j2" src python
|
||||||
#!/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!).
|
|
||||||
"""
|
|
||||||
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
import subprocess
|
|
||||||
import xml.etree.ElementTree 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" default="true">{}</setting>
|
|
||||||
</settings>"""
|
|
||||||
|
|
||||||
|
|
||||||
def get_output_names():
|
|
||||||
"""
|
|
||||||
get display name from xrandr output for given DISPLAY environment variable
|
|
||||||
"""
|
|
||||||
xrandr_output = [
|
|
||||||
l for l in subprocess.check_output(
|
|
||||||
["xrandr"],
|
|
||||||
env={"DISPLAY": os.environ["DISPLAY"]}
|
|
||||||
).decode("utf-8").splitlines()
|
|
||||||
]
|
|
||||||
return [l.split()[0] for l in xrandr_output if " connected " in l]
|
|
||||||
|
|
||||||
|
|
||||||
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 FileNotFoundError:
|
|
||||||
print("{} not found, creating stub file".format(template_path))
|
|
||||||
xml_template = ET.fromstring(template.format(output))
|
|
||||||
xml_tree = ET.ElementTree(xml_template)
|
|
||||||
finally:
|
|
||||||
xml_tree.write(template_path)
|
|
||||||
return xml_tree
|
|
||||||
|
|
||||||
|
|
||||||
def backup_videoscreen():
|
|
||||||
"""parse guisettings.xml for display name an backup videoscreen data"""
|
|
||||||
tree = parse_template(GUISETTINGS, VIDEOSCREEN_TEMPLATE, "Default")
|
|
||||||
root = tree.getroot()
|
|
||||||
videoscreen = root.find("./setting[@id='videoscreen.monitor']")
|
|
||||||
output = videoscreen.text
|
|
||||||
xml_path = os.path.join(CACHE_DIR, '{}-videodevice.xml'.format(output))
|
|
||||||
base_tree = ET.fromstring('<settings version="2"></settings>')
|
|
||||||
xml_tree = ET.ElementTree(base_tree)
|
|
||||||
backup_root = xml_tree.getroot()
|
|
||||||
backup_root.insert(0, videoscreen)
|
|
||||||
xml_tree.write(xml_path)
|
|
||||||
print("written backup for {} to {}".format(output, xml_path))
|
|
||||||
|
|
||||||
|
|
||||||
def change_videoscreen(output, new_videoscreen):
|
|
||||||
"""change videoscreen node to content of backup file"""
|
|
||||||
tree = parse_template(GUISETTINGS, VIDEOSCREEN_TEMPLATE, output)
|
|
||||||
root = tree.getroot()
|
|
||||||
|
|
||||||
videoscreen = root.find('./setting[@id="videoscreen.monitor"]')
|
|
||||||
if videoscreen is not None:
|
|
||||||
videoscreen.text = new_videoscreen.text
|
|
||||||
else:
|
|
||||||
videoscreen = root.find("./settings")
|
|
||||||
root.insert(0, new_videoscreen)
|
|
||||||
tree.write(GUISETTINGS)
|
|
||||||
return tree
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
output = get_output_names()[0]
|
|
||||||
if not output:
|
|
||||||
sys.exit("Error: no screen name found")
|
|
||||||
try:
|
|
||||||
os.makedirs(CACHE_DIR, exist_ok=True)
|
|
||||||
except PermissionError:
|
|
||||||
sys.exit("Error: insufficient permissions to create cachedir {}".format(
|
|
||||||
CACHE_DIR))
|
|
||||||
try:
|
|
||||||
backup_videoscreen()
|
|
||||||
except FileNotFoundError:
|
|
||||||
print("{} does not exist".format(GUISETTINGS))
|
|
||||||
except Exception as e:
|
|
||||||
print("Could not backup videoscreen.monitor:", str(e))
|
|
||||||
xml_path = os.path.join(CACHE_DIR, '{}-videodevice.xml'.format(output))
|
|
||||||
videodir_xml = parse_template(xml_path, VIDEOSCREEN_TEMPLATE, output)
|
|
||||||
videodir_root = videodir_xml.getroot()
|
|
||||||
new_videoscreen = videodir_root.find("./setting[@id='videoscreen.monitor']")
|
|
||||||
guisettings_xml = change_videoscreen(output, new_videoscreen)
|
|
||||||
#+END_SRC
|
|
||||||
*** files
|
*** files
|
||||||
:PROPERTIES:
|
:PROPERTIES:
|
||||||
:ID: 58c5c693-bd24-420a-bfed-79771e8e0d47
|
:ID: 58c5c693-bd24-420a-bfed-79771e8e0d47
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
name:
|
name:
|
||||||
- kodi
|
- kodi
|
||||||
- kodi-pvr-vdr-vnsi
|
- kodi-pvr-vdr-vnsi
|
||||||
|
- python3-lxml
|
||||||
state: present
|
state: present
|
||||||
install_recommends: no
|
install_recommends: no
|
||||||
|
|
||||||
|
@ -4,40 +4,64 @@
|
|||||||
|
|
||||||
This Script changes the monitor in KODI's guisettings.xml to the wanted output
|
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!).
|
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 os
|
||||||
import sys
|
import sys
|
||||||
import subprocess
|
import subprocess
|
||||||
import xml.etree.ElementTree as ET
|
from lxml import etree as ET
|
||||||
|
|
||||||
|
|
||||||
GUISETTINGS = '/var/lib/vdr/.kodi/userdata/guisettings.xml'
|
GUISETTINGS = '/var/lib/vdr/.kodi/userdata/guisettings.xml'
|
||||||
CACHE_DIR = '/var/lib/vdr/.kodi/.display_cache'
|
CACHE_DIR = '/var/lib/vdr/.kodi/.display_cache'
|
||||||
VIDEOSCREEN_TEMPLATE = """<settings version="2">
|
VIDEOSCREEN_TEMPLATE = """<settings version="2">
|
||||||
<setting id="videoscreen.monitor" default="true">{}</setting>
|
<setting id="videoscreen.monitor">{}</setting>
|
||||||
</settings>"""
|
</settings>"""
|
||||||
|
|
||||||
|
|
||||||
def get_output_names():
|
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
|
get display name from xrandr output for given DISPLAY environment variable
|
||||||
"""
|
"""
|
||||||
|
try:
|
||||||
xrandr_output = [
|
xrandr_output = [
|
||||||
l for l in subprocess.check_output(
|
l for l in subprocess.check_output(
|
||||||
["xrandr"],
|
["xrandr"],
|
||||||
env={"DISPLAY": os.environ["DISPLAY"]}
|
env={"DISPLAY": os.environ["DISPLAY"]}
|
||||||
).decode("utf-8").splitlines()
|
).decode("utf-8").splitlines()
|
||||||
]
|
]
|
||||||
return [l.split()[0] for l in xrandr_output if " connected " in l]
|
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=""):
|
def parse_template(template_path, template, output=""):
|
||||||
"""read videoscreen settings from backup or create a stub file"""
|
"""read videoscreen settings from backup or create a stub file"""
|
||||||
try:
|
try:
|
||||||
xml_tree = ET.parse(template_path)
|
xml_tree = ET.parse(template_path)
|
||||||
except FileNotFoundError:
|
except OSError:
|
||||||
print("{} not found, creating stub file".format(template_path))
|
print(f"{template_path} not found, creating stub file", file=sys.stderr)
|
||||||
xml_template = ET.fromstring(template.format(output))
|
xml_template = ET.fromstring(template.format(output))
|
||||||
xml_tree = ET.ElementTree(xml_template)
|
xml_tree = ET.ElementTree(xml_template)
|
||||||
finally:
|
finally:
|
||||||
@ -45,52 +69,49 @@ def parse_template(template_path, template, output=""):
|
|||||||
return xml_tree
|
return xml_tree
|
||||||
|
|
||||||
|
|
||||||
def backup_videoscreen():
|
def main(output):
|
||||||
"""parse guisettings.xml for display name an backup videoscreen data"""
|
guisettings = parse_template(GUISETTINGS, VIDEOSCREEN_TEMPLATE, "Default")
|
||||||
tree = parse_template(GUISETTINGS, VIDEOSCREEN_TEMPLATE, "Default")
|
|
||||||
root = tree.getroot()
|
# parse guisettings Etree for display name an backup videoscreen data
|
||||||
videoscreen = root.find("./setting[@id='videoscreen.monitor']")
|
root = guisettings.getroot()
|
||||||
output = videoscreen.text
|
old_output = root.find("./setting[@id='videoscreen.monitor']").text
|
||||||
xml_path = os.path.join(CACHE_DIR, '{}-videodevice.xml'.format(output))
|
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>')
|
base_tree = ET.fromstring('<settings version="2"></settings>')
|
||||||
xml_tree = ET.ElementTree(base_tree)
|
xml_tree = ET.ElementTree(base_tree)
|
||||||
backup_root = xml_tree.getroot()
|
backup_root = xml_tree.getroot()
|
||||||
backup_root.insert(0, videoscreen)
|
|
||||||
|
# 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)
|
xml_tree.write(xml_path)
|
||||||
print("written backup for {} to {}".format(output, xml_path))
|
print(f"written backup for {old_output} to {xml_path}", file=sys.stderr)
|
||||||
|
|
||||||
|
# change videoscreen node to content of backup file
|
||||||
def change_videoscreen(output, new_videoscreen):
|
xml_path = os.path.join(CACHE_DIR, f'{output}-videoscreen.xml')
|
||||||
"""change videoscreen node to content of backup file"""
|
|
||||||
tree = parse_template(GUISETTINGS, VIDEOSCREEN_TEMPLATE, output)
|
|
||||||
root = tree.getroot()
|
|
||||||
|
|
||||||
videoscreen = root.find('./setting[@id="videoscreen.monitor"]')
|
|
||||||
if videoscreen is not None:
|
|
||||||
videoscreen.text = new_videoscreen.text
|
|
||||||
else:
|
|
||||||
videoscreen = root.find("./settings")
|
|
||||||
root.insert(0, new_videoscreen)
|
|
||||||
tree.write(GUISETTINGS)
|
|
||||||
return tree
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
output = get_output_names()[0]
|
|
||||||
if not output:
|
|
||||||
sys.exit("Error: no screen name found")
|
|
||||||
try:
|
|
||||||
os.makedirs(CACHE_DIR, exist_ok=True)
|
|
||||||
except PermissionError:
|
|
||||||
sys.exit("Error: insufficient permissions to create cachedir {}".format(
|
|
||||||
CACHE_DIR))
|
|
||||||
try:
|
|
||||||
backup_videoscreen()
|
|
||||||
except FileNotFoundError:
|
|
||||||
print("{} does not exist".format(GUISETTINGS))
|
|
||||||
except Exception as e:
|
|
||||||
print("Could not backup videoscreen.monitor:", str(e))
|
|
||||||
xml_path = os.path.join(CACHE_DIR, '{}-videodevice.xml'.format(output))
|
|
||||||
videodir_xml = parse_template(xml_path, VIDEOSCREEN_TEMPLATE, output)
|
videodir_xml = parse_template(xml_path, VIDEOSCREEN_TEMPLATE, output)
|
||||||
videodir_root = videodir_xml.getroot()
|
videodir_root = videodir_xml.getroot()
|
||||||
new_videoscreen = videodir_root.find("./setting[@id='videoscreen.monitor']")
|
videoscreen = videodir_root.find("./setting[@id='videoscreen.monitor']")
|
||||||
guisettings_xml = change_videoscreen(output, new_videoscreen)
|
# 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)
|
||||||
|
Loading…
Reference in New Issue
Block a user