diff --git a/Manual.html b/Manual.html index 276f39f..33f4f3e 100644 --- a/Manual.html +++ b/Manual.html @@ -3,7 +3,7 @@ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> - + Ansible Playbooks for yaVDR 0.7 @@ -236,10 +236,6349 @@ for the JavaScript code in this tag.

Ansible Playbooks for yaVDR 0.7

+
+

Inhaltsverzeichnis

+
+ +
+
+
+

1 User Stories

+
+
+
+

1.1 yavdr-full

+
+

+A User wants to install yaVDR without customization and relies on full automation. +

+ +

+After installing a supported Ubuntu Server version and (if needed) setting up the network connection, the install script is downloaded and started. +

+ +

+The install script adds the ansible PPA, installs ansible and other basic dependencies and runs the automated installation process. +

+ +

+Several roles are used to tie everything together: +

+
+
yavdr-common
installs the basic set of packages needed and preconfigures the system (package sources, package manager settings, entires for network ports, directory structure etc.). Also collects information about the system
+
autoinstall-ubuntu-drivers
uses Ubuntu’s automatic detection for additional drivers (e.g. proprietary nvidia driver, microcode updates, VirtualBox guest additions)
+
vdr
install the vdr package and required plugins
+
pulseaudio
install and preconfigure pulseaudio
+
yavdr-network
configure WOL, add nfs client capabilites, install avahi-linker
+
samba-server
install and preconfigure a samba server
+
nfs-server
install nfs-kernelserver and preconfigure nfs exports (and avahi-announcements)
+
autoinstall-satip
install vdr-plugin-satip if a Sat>IP server has been found
+
autoinstall-targavfd
install vdr-plugin-targavfd if display is connected
+
autoinstall-imonlcd
install vdr-plugin-imonlcd if a matchind display is connected
+
yavdr-xorg
install and configure a systemd user session with a running X-server. A frontend script will manage VDR’s frontend and other applications like KODI. Also choose the best possible output plugin.
+
grub-config
update grub configuration based on executed roles
+
+
+ +
+

1.1.1 Using vdr, pulseaudio and xorg together

+
+
+
+ +
+

2 Introduction

+
+

+One of the major problems we faced with customized Ubuntu ISO files as installation media for prior yaVDR versions has been the limited hardware support and the time consuming process to create and update them. An interesting alternative to this approach is to enable the user to choose the installation medium himself so point releases, kernel versions and additional drivers can be chosen deliberately. After the basic setup is complete (and a working internet connection is available), a fully customizable install script completes the yaVDR installation. +

+
+
+
+

3 Installing and configuring yaVDR with Ansible

+
+

+This is an experimental feature which allows to set up a yaVDR installation based on a normal Ubuntu Server 16.04.x installation using Ansible. +

+ +

+This Manual is written in org-mode for Emacs and can rewrite the complete ansible configuration if you call org-babel-tangle from within emacs. +

+ +

+To use this playbook on a Ubuntu Server Installation you need to run the following commands: +

+
+
sudo apt-get install git
+git clone https://github.com/yavdr/yavdr-ansible.git
+cd yavdr-ansible
+sudo ./install-yavdr.sh
+
+
+ +

+We use a callback to generate tags for all roles autmatically: +

+
+
[defaults]
+callback_plugins = plugins/callbacks
+callback_whitelist = auto_tags
+ansible_managed = *** ANSIBLE MANAGED FILE ***
+  template: {file}
+
+
+
+ +
+

3.1 Install script for local usage

+
+
+
if (( $EUID != 0 )); then
+    echo "This script must be run using sudo -H or as root"
+    exit
+fi
+
+apt-get -y install software-properties-common
+# Add repository for ansible
+add-apt-repository -y ppa:yavdr/experimental-main
+# update packages
+apt-get update
+# install required packages
+apt-get -y install --no-install-recommends ansible
+
+# TODO: run ansible on local host
+ansible-playbook yavdr07.yml -b -i 'localhost_inventory' --connection=local --tags="all" --extra-vars "first_run=True"
+
+
+
+
+
+
+

4 Playbooks

+
+
+
+

4.1 yavdr07.yml

+
+

+The yavdr07.yml playbook sets up a fully-featured yaVDR installation: +

+
+
---
+# file: yavdr07.yml
+# this playbook sets up a complete yaVDR 0.7 installation
+
+- name: set up yaVDR
+  hosts: all
+  become: true
+  roles:
+     - yavdr-common               # install and configure the basic system
+     - collect-facts              # query system facts
+     - autoinstall-ubuntu-drivers # use ubuntu-drivers to install proprietary dirvers
+                                  # (e.g. nvidia, virtualbox)
+     - autoinstall-virtualbox-guest
+     # - nvidia-387                # install very recent nvidia-387 from ppa:graphics-drivers/ppa
+     - vdr                        # install vdr and related packages
+     - yavdr-network              # enable network client capabilities
+     - samba-install              # install samba server
+     - samba-config               # configure samba server
+     - nfs-server                 # install nfs server
+     - pulseaudio                 # install pulseaudio
+     - yavdr-xorg                 # graphical session
+     - yavdr-remote               # remote configuration files, services and scripts
+     - autoinstall-satip          # install vdr-plugin-satip if a Sat>IP server has been found
+     - autoinstall-targavfd       # install vdr-plugin-targavfd if display is connected
+     - autoinstall-imonlcd        # install vdr-plugin-imonlcd if a matchind display is connected
+     - autoinstall-pvr350         # install vdr-plugin-pgvr350 if a matching card is detected
+     - autoinstall-hauppauge-pvr  # install vdr-plugin-pvrinput if a matching card is found
+     - autoinstall-dvbsddevice    # install vdr-plugin-dvbsddevice if a matching card is detected
+     - autoinstall-hardware-irmp  # install yavdr-hardware-irmp if a matching usb device is detected
+     - autoinstall-atric-usb      # preconfigure lircd for Atric IR-WakeupUSB receiver
+     - autoinstall-yausbir        # preconfigure lircd for yaUsbIR receiver
+     - autoinstall-dvbsky-firmware # download an install required firmware files for dvbsky cards
+     - kodi
+     - dvd                        # set up packages and a udev rule to allow kodi and other players
+                                  # to play and eject optical media
+     - wakeup                     # set up wakeup methods for rtc etc.
+     - grub-config                # configure grub
+
+  handlers:
+    - import_tasks: handlers/main.yml
+
+
+
+
+
+

4.2 yavdr07-headless.yml

+
+

+For a headless server installation yavdr07-headless.yml is a good choice +

+
+
---
+# file: yavdr07-headless.yml
+# this playbook set up a headless yaVDR 0.7 installation
+
+- name: set up a headless yaVDR server
+  hosts: all
+  become: true
+  roles:
+    - yavdr-common
+    - collect-facts              # query system facts
+    - vdr
+    - yavdr-network
+    - samba-server
+    - samba-config
+    - nfs-server
+    - grub-config
+    - autoinstall-satip
+    - wakeup
+  tags:
+    - always
+  handlers:
+    - import_tasks: handlers/main.yml
+
+
+
+
+
+
+

5 Hosts

+
+

+This playbook can either be used to run the installation on the localhost or any other PC in the network that can be accessed via ssh. Simply add the host names or IP addresses to the hosts file in the respective section: +

+ +
+
[local]
+localhost connection=local
+
+
+
+
+
+
+

6 Group Variables

+
+
+
+

6.1 PPAs

+
+
+
---
+# file: group_vars/all
+
+branch: experimental
+ppa_owner: 'ppa:yavdr'
+# add the following PPAs
+repositories:
+  - '{{ ppa_owner }}/{{branch}}-main'
+  - '{{ ppa_owner }}/{{branch}}-vdr'
+  #- '{{ ppa_owner }}/{{branch}}-yavdr'
+  #- '{{ ppa_owner }}/{{branch}}-kodi'
+
+
+
+
+
+

6.2 VDR user, directories, special configuration and plugins

+
+
+
# properties of the user vdr and vdr-related options
+vdr:
+  user: vdr
+  group: vdr
+  uid: 666
+  gid: 666
+  home: /var/lib/vdr
+  confdir: /var/lib/vdr
+  recdir: /srv/vdr/video
+  hide_first_recording_level: false
+  safe_dirnames: true  # escape characters (useful for windows clients and FAT/NTFS file systems)
+  override_vdr_charset: false
+
+# add the vdr plugins you want to install
+vdr_plugins:
+  - vdr-plugin-devstatus
+  - vdr-plugin-markad
+  - vdr-plugin-restfulapi
+  - vdr-plugin-softhddevice-vpp
+
+
+
+
+
+

6.3 Media directories

+
+
+
# dictionary of directories for (shared) files. Automatically exported via NFS and Samba if those roles are enabled
+media_dirs:
+  audio: /srv/audio
+  video: /srv/video
+  pictures: /srv/picture
+  files: /srv/files
+  backups: /srv/backups
+  recordings: '{{ vdr.recdir }}'
+
+
+
+
+
+

6.4 NFS

+
+
+
nfs:
+  insecure: false  # set to true for OS X clients or if you plan to use libnfs as unprivileged user (e.g. KODI)
+
+
+
+
+
+

6.5 Samba

+
+
+
samba:
+  workgroup: YAVDR
+  windows_compatible: '{{ vdr.safe_dirnames }}'  # set to true to disable unix extensions, enable follow symlinks and wide links
+
+
+
+
+
+

6.6 Additional packages

+
+
+
# additional packages you want to install
+extra_packages:
+  - bpython
+  - bpython3
+  - htop
+  - tree
+  - vim
+  - w-scan
+  - plymouth-theme-yavdr-logo
+
+
+
+
+
+

6.7 System pre-configuration

+
+
+
frontend: vdr
+#system:
+#  shutdown: poweroff
+wakeup_method: acpiwakeup
+grub:
+  timeout: 0
+  boot_options: quiet splash
+
+
+
+
+
+
+

7 Roles

+
+
+
+

7.1 install-dependencies

+
+
+
+

7.1.1 tasks

+
+
+
    +
  1. main.yml
    +
    +
    +
    ---
    +
    +- name: apt | install packages
    +  apt:
    +    name: '{{ item }}'
    +    state: present
    +    install_recommends: no
    +  with_items:
    +    '{{ packages }}'
    +
    +
    +
    +
  2. +
+
+
+ +
+

7.2 nvidia-387 drivers

+
+

+install nvidia-387 from ppa:graphics-drivers/ppa +

+
+
+

7.2.1 tasks

+
+
+
    +
  1. main.yml
    +
    +
    +
    ---
    +
    +- name: add ppa:graphics-drivers/ppa
    +  apt_repository:
    +      repo: 'ppa:graphics-drivers/ppa'
    +      state: present
    +      update_cache: yes
    +  tags:
    +    - ppa
    +
    +- name: install nvidia-387 and other required packages
    +  apt:
    +    name: '{{ item }}'
    +    state: present
    +    install_recommends: no
    +  with_items:
    +    - nvidia-387
    +    - nvidia-settings
    +  tags:
    +    - packages
    +
    +
    +
    +
  2. +
+
+
+
+

7.3 yavdr-common

+
+

+This role is used to set up a basic yaVDR installation. It creates the directories, installs the vdr and other useful packages. +

+
+
+

7.3.1 default variables

+
+

+This section is for reference only, please use the files in global_vars for customizations. +

+
+
---
+# file: roles/yavdr-common/defaults/main.yml
+
+
+
+ +
    +
  1. Repositories
    +
    +

    +You can set a list of package repositories which provide the necessary packages. Feel free to use own PPAs if you need special customization to the VDR and it’s plugins. +

    +
    +
    branch: unstable
    +repositories:
    +  - 'ppa:yavdr/main'
    +  - 'ppa:yavdr/unstable-main'
    +  - 'ppa:yavdr/{{branch}}-vdr'
    +  - 'ppa:yavdr/{{branch}}-kodi'
    +  - 'ppa:yavdr/{{branch}}-yavdr'
    +
    +
    +
    +
  2. +
  3. Drivers
    +
    +

    +Automatically installed drivers can be very useful, but if you know you need a certain driver, you can simply set it’s value to true. If you don’t want a driver to be installed, set it’s value to false. +

    +
    +
    drivers:
    +  sundtek: auto
    +  ddvb-dkms: auto
    +
    +
    +
    +
  4. +
  5. Additional Packages
    +
    +

    +Add additional packages you would like to have on your installation to this list +

    +
    +
    extra_packages:
    +  - vim
    +  - tree
    +  - w-scan
    +
    +
    +
    +
  6. +
  7. VDR
    +
    +

    +This section allows you to set the recording directory, the user and group that runs the vdr and it’s home directory. +

    +
    +
    user
    the vdr user name
    +
    group
    the main group for the user vdr
    +
    uid
    the user id for the user vdr
    +
    gid
    the group id for the group vdr
    +
    home
    the home directory for the user vdr
    +
    recdir
    the recording directory used by VDR
    +
    hide_first_recording_level
    let vdr hide the first directory level of it’s recording directory so the content of multiple directories is shown merged together
    +
    safe_dirnames
    replace special characters which are not compatible with Windows file systems and Samba shares
    +
    override_vdr_charset
    workaround for channels with weird EPG encodings, e.g. Sky
    +
    +
    +
    vdr:
    +    user: vdr
    +    group: vdr
    +    uid: 666
    +    gid: 666
    +    home: /var/lib/vdr
    +    recdir: /srv/vdr/video
    +    hide_first_recording_level: false
    +    safe_dirnames: true
    +    override_vdr_charset: false
    +
    +
    +
    +
  8. +
+
+
+

7.3.2 tasks

+
+

+yavdr-common executes the following tasks: +

+
+
    +
  1. main.yml
    +
    +
    +
    ---
    +# file: roles/yavdr-common/tasks/main.yml 
    +
    +- name: basic installation
    +  block:
    +        - import_tasks: configure_apt.yml
    +        - import_tasks: configure_system.yml
    +        - import_tasks: create_directories.yml
    +  tags: [install]
    +
    +
    +
    +
      +
    1. Disable default installation of recommended packages
      +
      +

      +This task prevents apt to automatically install all recommended dependencies for packages: +

      +
      +
      ---
      +
      +- name: apt | prevent automatic installation of recommended packages
      +  template:
      +    src: templates/90-norecommends.j2
      +    dest: /etc/apt/apt.conf.d/90norecommends
      +
      +
      +
      +
      +
    2. +
    3. Set up package repositories
      +
      +
      +
      - name: add PPAs
      +  apt_repository:
      +      repo: '{{ item }}'
      +      state: present
      +      update_cache: yes
      +  with_items: '{{ repositories }}'
      +  tags:
      +    - ppa
      +
      +- name: run apt-get dist-upgrade
      +  apt:
      +      upgrade: dist
      +      update_cache: yes
      +
      +
      +
      +
    4. +
    5. Use bash instead of dash
      +
      +
      +
      - name: use bash instead of dash
      +  shell: |
      +    echo "set dash/sh false" | debconf-communicate
      +    dpkg-reconfigure -f noninteractive dash
      +
      +
      +
      +
    6. + +
    7. create user vdr
    8. +
    9. Disable release-upgrade notifications
      +
        +
      1. SOMEDAY move from lineinfile to template
        +
        +
        +
        - name: disable release-upgrade notifications
        +  lineinfile:
        +    dest: /etc/update-manager/release-upgrades
        +    backrefs: yes
        +    state: present
        +    regexp: '^(Prompt=).*$'
        +    line: '\1never'
        +  ignore_errors: yes
        +  with_first_found:
        +    - files:
        +      - /etc/update-manager/release-upgrades
        +      skip: true
        +
        +
        +
        +
        +
      2. +
      +
    10. +
    11. Install essential packages
      +
      +
      +
      - name: apt | install basic packages
      +  apt:
      +    name: '{{ item }}'
      +    state: present
      +    install_recommends: no
      +  with_items:
      +    - anacron
      +    - acl
      +    - at
      +    - bash-completion
      +    #- biosdevname  # caution: may change device names after a minimal installation!
      +    - debconf-utils
      +    - linux-firmware
      +    - psmisc
      +    - python-kmodpy
      +    - python-requests
      +    - python-usb
      +    - python3-usb
      +    - software-properties-common
      +    - ssh
      +    - wget
      +    - wpasupplicant
      +    - usbutils
      +    - xfsprogs
      +
      +
      +
      +
      +
    12. +
    13. Install additional packages (user defined)
      +
      +
      +
      - name: apt | install extra packages
      +  apt:
      +    name: '{{ item }}'
      +    state: present
      +    install_recommends: no
      +  with_items:
      +      '{{ extra_packages }}'
      +
      +
      +
      +
    14. +
    15. create directories
    16. +
    +
  2. +
+
+
+

7.3.3 templates

+
+
+
{{ ansible_managed | comment('c') }}
+// Recommends are as of now still abused in many packages
+APT::Install-Recommends "0";
+APT::Install-Suggests "0";
+
+
+
+
+
+
+

7.4 collect facts about the system with custom modules

+
+
+
+

7.4.1 variables

+
+
+
first_run: False
+
+
+
+
+
+

7.4.2 tasks

+
+
+
    +
  1. main.yml
    +
    +
    +
    - name: get information about usb and pci hardware and loaded kernel modules
    +  hardware_facts:
    +    usb: True
    +    pci: True
    +    modules: True
    +    gpus: True
    +    acpi_power_modes: True
    +  tags:
    +    - always
    +
    +- debug:
    +    var: '{{ item }}'
    +    verbosity: 1
    +  with_items:
    +    - usb
    +    - pci
    +    - gpus
    +    - modules
    +    - acpi_power_modes
    +    - nvidia_detected
    +    - intel_detected
    +    - amd_detected
    +    - virtualbox_detected
    +
    +- name: known vdr output plugins
    +  set_fact:
    +    vdr_output_plugins:    
    +      - softhddevice
    +      - xineliboutput
    +      - xine
    +
    +
    +
    +
  2. +
+
+
+
+

7.5 vdr

+
+
+
+

7.5.1 tasks

+
+
+
    +
  1. install the basic vdr packages
    +
    +
    +
    ---
    +# file: roles/vdr/tasks/main.yml
    +
    +- name: apt | install basic vdr packages
    +  apt:
    +    name: '{{ item }}'
    +    state: present
    +    install_recommends: no
    +  with_items:
    +    - vdr
    +    - vdrctl
    +    - vdr-plugin-dbus2vdr
    +
    +
    +
    +
  2. +
  3. Add svdrp/svdrp-disc to /etc/services
    +
    +
    +
    - name: add svdrp and svdrp-disc to /etc/services
    +  lineinfile:
    +    dest: /etc/services
    +    state: present
    +    line: "{{ item }}"
    +  with_items:
    +    - "svdrp            6419/tcp"
    +    - "svdrp-disc       6419/udp"
    +
    +
    +
    +
  4. +
  5. Set up the recording directory for the vdr user
    +
    +
    +
    - name: create vdr recdir
    +  file:
    +    state: directory
    +    owner: '{{ vdr.user }}'
    +    group: '{{ vdr.group }}'
    +    mode: 0775
    +    dest: '{{ vdr.recdir }}'
    +
    +- name: set option to use hide-first-recording-level patch
    +  blockinfile:
    +    dest: /etc/vdr/conf.d/04-vdr-hide-first-recordinglevel.conf
    +    create: true
    +    state: "{{ 'present' if vdr.hide_first_recording_level else 'absent' }}"
    +    block: |
    +      [vdr]
    +      --hide-first-recording-level
    +
    +- name: create local dir in recdir
    +  file:
    +    state: directory
    +    owner: '{{ vdr.user }}'
    +    group: '{{ vdr.group }}'
    +    mode: '0775'
    +    dest: '{{ vdr.recdir }}/local'
    +  when:
    +    vdr.hide_first_recording_level
    +
    +# TODO: set recdir, user etc. in /etc/vdr/conf.d/
    +
    +
    +
    +
  6. +
  7. Install additional vdr plugins
    +
    +

    +The additional plugins to install can be set in the variable {{vdr_plugins}} in the group variables +

    +
    +
    - name: apt | install additional vdr plugins
    +  apt:
    +    name: '{{ item }}'
    +    state: present
    +    install_recommends: no
    +  with_items:
    +    '{{ vdr_plugins | default({}) }}'
    +  notify: [ 'Restart VDR' ]
    +
    +
    +
    +
  8. +
  9. copy vdr configuration files (if they don’t exist yet)
    +
    +
    +
    - name: ensure vdr is stopped
    +  systemd:
    +    name: vdr.service
    +    state: stopped
    +  notify: [ 'Start VDR' ]
    +
    +- name: "vdr configuration | copy remote.conf if it doesn't exist yet"
    +  copy:
    +    src: files/remote.conf
    +    dest: '{{ vdr.confdir }}/remote.conf'
    +    owner: '{{ vdr.user }}'
    +    group: '{{ vdr.group }}'
    +    mode: 0644
    +    force: no
    +
    +- name: "vdr configuration | copy keymacros.conf if it doesn't exist yet"
    +  copy:
    +    src: files/keymacros.conf
    +    dest: '{{ vdr.confdir }}/keymacros.conf'
    +    owner: '{{ vdr.user }}'
    +    group: '{{ vdr.group }}'
    +    mode: 0644
    +    force: no
    +
    +
    +
    +
  10. +
+
+ +
+

7.5.2 templates

+
+
+

7.5.3 files

+
+
+
    +
  1. remote.conf
    +
    +
    +
    LIRC.Up KEY_UP
    +LIRC.Down KEY_DOWN
    +LIRC.Menu KEY_MENU
    +LIRC.Ok KEY_OK
    +LIRC.Back KEY_ESC
    +LIRC.Left KEY_LEFT
    +LIRC.Right KEY_RIGHT
    +LIRC.Red KEY_RED
    +LIRC.Green KEY_GREEN
    +LIRC.Yellow KEY_YELLOW
    +LIRC.Blue KEY_BLUE
    +LIRC.0 KEY_0
    +LIRC.1 KEY_1
    +LIRC.2 KEY_2
    +LIRC.3 KEY_3
    +LIRC.4 KEY_4
    +LIRC.5 KEY_5
    +LIRC.6 KEY_6
    +LIRC.7 KEY_7
    +LIRC.8 KEY_8
    +LIRC.9 KEY_9
    +LIRC.Info KEY_INFO
    +LIRC.Play KEY_PLAY
    +LIRC.Pause KEY_PAUSE
    +LIRC.Play/Pause KEY_PLAYPAUSE
    +LIRC.Stop KEY_STOP
    +LIRC.Record KEY_RECORD
    +LIRC.FastFwd KEY_FASTFORWARD
    +LIRC.FastRew KEY_REWIND
    +LIRC.Next KEY_NEXT
    +LIRC.Prev KEY_BACK
    +LIRC.Power KEY_POWER2
    +LIRC.Channel+ KEY_CHANNELUP
    +LIRC.Channel- KEY_CHANNELDOWN
    +LIRC.PrevChannel KEY_PREVIOUS
    +LIRC.Volume+ KEY_VOLUMEUP
    +LIRC.Volume- KEY_VOLUMEDOWN
    +LIRC.Mute KEY_MUTE
    +LIRC.Subtitles KEY_SUBTITLE
    +LIRC.Schedule KEY_EPG
    +LIRC.Channels KEY_CHANNEL
    +LIRC.Commands KEY_FAVORITES
    +LIRC.Audio KEY_MODE
    +LIRC.Timers KEY_TIME
    +LIRC.Recordings KEY_PVR
    +LIRC.Setup KEY_SETUP
    +LIRC.User0 KEY_TEXT
    +LIRC.User1 KEY_PROG1
    +LIRC.User2 KEY_PROG2
    +LIRC.User3 KEY_PROG3
    +LIRC.User4 KEY_PROG4
    +LIRC.User5 KEY_AUDIO
    +LIRC.User6 KEY_VIDEO
    +LIRC.User7 KEY_IMAGES
    +LIRC.User8 KEY_FN
    +LIRC.User9 KEY_SCREEN
    +
    +XKeySym.Up         Up
    +XKeySym.Down       Down
    +XKeySym.Menu       Home
    +XKeySym.Menu       Tab
    +XKeySym.Menu       KP_Home
    +XKeySym.Ok         Return
    +XKeySym.Ok         KP_Enter
    +XKeySym.Back       BackSpace
    +XKeySym.Back       KP_Separator
    +XKeySym.Left       Left
    +XKeySym.Right      Right
    +XKeySym.Up         KP_Up
    +XKeySym.Down       KP_Down
    +XKeySym.Left       KP_Left
    +XKeySym.Right      KP_Right
    +XKeySym.Red        F1
    +XKeySym.Green      F2
    +XKeySym.Yellow     F3
    +XKeySym.Blue       F4
    +XKeySym.0          0
    +XKeySym.1          1
    +XKeySym.2          2
    +XKeySym.3          3
    +XKeySym.4          4
    +XKeySym.5          5
    +XKeySym.6          6
    +XKeySym.7          7
    +XKeySym.8          8
    +XKeySym.9          9
    +XKeySym.0          KP_0
    +XKeySym.1          KP_1
    +XKeySym.2          KP_2
    +XKeySym.3          KP_3
    +XKeySym.4          KP_4
    +XKeySym.5          KP_5
    +XKeySym.6          KP_6
    +XKeySym.7          KP_7
    +XKeySym.8          KP_8
    +XKeySym.9          KP_9
    +XKeySym.Info       End
    +XKeySym.Info       KP_End
    +XKeySym.Pause      F9
    +XKeySym.FastFwd    F6
    +XKeySym.FastRew    F5
    +XKeySym.Power      Pause
    +XKeySym.Volume+    F12
    +XKeySym.Volume-    F11
    +XKeySym.Volume+    KP_Add
    +XKeySym.Volume-    KP_Subtract
    +XKeySym.Mute       F10
    +XKeySym.User1      F5
    +XKeySym.User2      F6
    +XKeySym.User3      F7
    +XKeySym.User4      F8
    +XKeySym.User5      Print
    +XKeySym.User6      Scroll_Lock
    +XKeySym.User7      Insert
    +XKeySym.User8      KP_Divide
    +XKeySym.User9      KP_Multiply
    +XKeySym.Audio      Menu
    +XKeySym.Channel+   Prior
    +XKeySym.Channel-   Next
    +XKeySym.Channel+   KP_Prior
    +XKeySym.Channel-   KP_Next
    +XKeySym.Volume+    XF86AudioRaiseVolume
    +XKeySym.Volume-    XF86AudioLowerVolume
    +XKeySym.Mute       XF86AudioMute
    +XKeySym.Stop       XF86AudioStop
    +XKeySym.Play/Pause  XF86AudioPlay
    +XKeySym.Prev       XF86AudioPrev
    +XKeySym.Next       XF86AudioNext
    +
    +
    +
    +
  2. +
  3. keymacros.conf
    +
    +
    +
    # Remote control key macros for VDR
    +#
    +# Format:
    +#
    +# macrokey  key1 key2 key3...
    +# macrokey  @plugin key1 key2 key3...
    +#
    +# See man vdr(5)
    +
    +Red       Recordings
    +Green     Schedule
    +Yellow    Info
    +Blue      Timers
    +User0     @osdteletext
    +
    +
    +
    +
    +
    +
  4. +
+
+
+
+

7.6 STARTED yavdr-network

+
+
+
+

7.6.1 default variables

+
+
+
install_avahi: true
+
+
+
+
+
+

7.6.2 tasks

+
+
+
---
+# this playbook sets up network services for a yaVDR installation
+
+- name: apt | install packages for network services
+  apt:
+      name: '{{ item }}'
+      state: present
+      install_recommends: no
+  with_items:
+      - avahi-daemon
+      - avahi-utils
+      #- biosdevname # caution: this may change device names after a minimal installation!
+      - ethtool
+      - nfs-common
+      - vdr-addon-avahi-linker
+      - wakeonlan
+
+# Does this really work? We need a way to check if an interface supports WOL - Python Skript?
+# - name: check WOL capabilities of network interfaces
+#   shell: 'ethtool {{ item }} | grep -Po "(?<=Supports\sWake-on:\s).*$"'
+#   register: wol
+#   with_items: '{% for interface in ansible_interfaces if interface != 'lo' and interface != 'bond0' %}'
+  
+- name: restart autofs if running
+  systemd:
+    name: autofs
+    state: restarted
+    enabled: yes
+    masked: no
+
+- name: ensure autofs is running
+  systemd:
+    name: autofs
+    state: started
+    enabled: yes
+    masked: no
+
+- name: restart avahi-linker if running
+  systemd:
+    name: avahi-linker
+    state: restarted
+    enabled: yes
+    masked: no
+
+- name: start avahi-linker
+  systemd:
+    name: avahi-linker
+    state: started
+    enabled: yes
+    masked: no
+
+- name: enable and start additional services for avahi-linker
+  systemd:
+    name: '{{ item }}'
+    state: started
+    enabled: yes
+    masked: no
+  with_items:
+    - vdr-net-monitor
+    - vdr-update-monitor
+    - prevent-umount-on-pause
+
+
+
+
+
+ +
+

7.7 nfs-server

+
+
+
+

7.7.1 TODO avahi-services für NFS beim Stoppen des nfs-kernel-servers depublizieren, beim Start wieder announcen

+
+
+

7.7.2 tasks

+
+
+
---
+
+- name: install nfs server packages
+  apt:
+    name: '{{ item }}'
+    state: present
+    install_recommends: no
+  with_items:
+    - nfs-kernel-server
+    - nfs-common
+
+- name: create /etc/exports
+  template:
+    src: templates/nfs-exports.j2
+    dest: /etc/exports
+  notify: [ 'Restart NFS Kernel Server' ]
+
+- name: populate /etc/avahi/services
+  template:
+    src: templates/avahi/service.j2
+    dest: '/etc/avahi/services/yavdr-{{ item.key }}.service'
+  with_dict: '{{ media_dirs }}'
+
+
+
+
+
+

7.7.3 templates

+
+
+
    +
  1. /etc/exports
    +
    +
    +
    /srv *(rw,fsid=0,sync,no_subtree_check,all_squash,anongid={{ vdr.gid }},anonuid={{ vdr.uid }})
    +{% for name, path in media_dirs.iteritems() %}
    +{{ path }} *(rw,fsid={{ loop.index }},sync,no_subtree_check,all_squash,anongid={{ vdr.gid }},anonuid={{ vdr.uid }}{{ ',insecure' if nfs.insecure else '' }})
    +{% endfor %}
    +
    +
    +
    +
  2. +
  3. avahi services
    +
    +
    +
    <?xml version="1.0" standalone='no'?>
    +<!DOCTYPE service-group SYSTEM "avahi-service.dtd">
    +<service-group>
    +<name replace-wildcards="yes">{{ item.key|capitalize }} on %h</name> ## Name
    +<service>
    +       <type>_nfs._tcp</type>
    +       <port>2049</port>
    +       <txt-record>path={{ item.value }}</txt-record> ## path to shared Folder
    +       <txt-record>subtype={{ 'vdr' if item.key == 'recordings' else item.key }}</txt-record> ## subtype
    +</service>
    +</service-group>
    +
    +
    +
    +
  4. +
+
+
+
+

7.8 STARTED yavdr-remote

+
+
+
+

7.8.1 default variables

+
+
+
lircd0_socket: /var/run/lirc/lircd0
+
+
+
+
+
+

7.8.2 tasks

+
+
+
---
+# This role is used to set up the yaVDR remote control configuration.
+
+- name: apt | install packages for remote support
+  apt:
+    name: '{{ item }}'
+    state: present
+  with_items:
+    - yavdr-remote
+    - lirc
+    - eventlircd
+    - lircd2uinput
+  tags:
+    - packages
+
+- name: add systemd drop-in for lircd to use lircd2uinput
+  block:
+    - name: create directory /etc/systemd/system/lircd.service.d/
+      file:
+        path: /etc/systemd/system/lircd.service.d/
+        state: directory
+    - name: expand template for /etc/systemd/system/lircd.service.d/lircd2uinput.conf
+      template:
+        src: templates/lircd.service.d/lircd2uinput.conf.j2
+        dest: /etc/systemd/system/lircd.service.d/lircd2uinput.conf
+  tags:
+    - config
+
+- name: stop, mask and disable lircd.socket, lircd.service and lircd-uinput.service # (the default lirc configuration conflicts with eventlircd)
+  systemd:
+    name: '{{ item }}'
+    enabled: no
+    state: stopped
+    masked: yes
+  with_items:
+    - lircd.service
+    - lircd.socket
+    - lircd-uinput.service
+  ignore_errors: yes
+  tags:
+    - systemd
+
+- name: configure vdr to read from a lircd-compatible socket
+  template:
+    src: templates/03-vdr-lirc.conf.j2
+    dest: /etc/vdr/conf.d/03-vdr-lirc.conf
+  notify: ['Restart VDR']
+  tags:
+    - config
+
+- name: expand template for /etc/rc_maps.cfg
+  template:
+    src: templates/rc_maps.cfg.j2
+    dest: /etc/rc_maps.cfg
+  notify: ['Trigger Udev']
+  tags:
+    - config
+
+
+
+
+
+

7.8.3 templates

+
+
+
    +
  1. Systemd Drop-in to start vdr with lirc support
    +
    +
    +
    {% if frontend != 'kodi' %}
    +[vdr]
    +--lirc=/var/run/lirc/lircd
    +{% endif %}
    +
    +
    +
    +
  2. +
  3. Systemd Drop-in to start lircd2uinput with lircd
    +
    +
    +
    [Service]
    +ExecStartPost=/usr/bin/lircd2uinput-add /var/run/lirc/lircd0
    +ExecStopPost=/usr/bin/lircd2uinput-remove /var/run/lirc/lircd0
    +
    +
    +
    +
  4. +
  5. create /etc/rc_maps.cfg
    +
    +
    +
    #
    +# Keymaps table
    +#
    +# This table creates an association between a keycode file and a kernel
    +# driver. It can be used to automatically override a keycode definition.
    +#
    +# Although not yet tested, it is mented to be added at udev.
    +#
    +# To use, you just need to run:
    +#   ./ir-keytable -a
    +#
    +# Or, if the remote is not the first device:
    +#   ./ir-keytable -a -s rc1     # for RC at rc1
    +#
    +
    +# Format:
    +#   driver - name of the driver provided via uevent - use * for any driver
    +#   table -  RC keymap table, provided via uevent - use * for any table
    +#   file - file name. If directory is not specified, it will default to
    +#       /etc/rc_keymaps.
    +# For example:
    +# driver    table               file
    +# cx8800    *               ./keycodes/rc5_hauppauge_new
    +# *     rc-avermedia-m135a-rm-jx    ./keycodes/kworld_315u
    +# saa7134   rc-avermedia-m135a-rm-jx    ./keycodes/keycodes/nec_terratec_cinergy_xs
    +# em28xx    *               ./keycodes/kworld_315u
    +# *     *               ./keycodes/rc5_hauppauge_new
    +
    +# Table to automatically load the rc maps for the bundled IR's provided with the
    +# devices supported by the linux kernel
    +
    +#driver table                    file
    +*   rc-adstech-dvb-t-pci     adstech_dvb_t_pci
    +*   rc-alink-dtu-m           alink_dtu_m
    +*   rc-anysee                anysee
    +*   rc-apac-viewcomp         apac_viewcomp
    +*   rc-asus-pc39             asus_pc39
    +*   rc-asus-ps3-100          asus_ps3_100
    +*   rc-ati-tv-wonder-hd-600  ati_tv_wonder_hd_600
    +*   rc-ati-x10               ati_x10
    +*   rc-avermedia-a16d        avermedia_a16d
    +*   rc-avermedia-cardbus     avermedia_cardbus
    +*   rc-avermedia-dvbt        avermedia_dvbt
    +*   rc-avermedia-m135a       avermedia_m135a
    +*   rc-avermedia-m733a-rm-k6 avermedia_m733a_rm_k6
    +*   rc-avermedia-rm-ks       avermedia_rm_ks
    +*   rc-avermedia             avermedia
    +*   rc-avertv-303            avertv_303
    +*   rc-azurewave-ad-tu700    azurewave_ad_tu700
    +*   rc-behold-columbus       behold_columbus
    +*   rc-behold                behold
    +*   rc-budget-ci-old         budget_ci_old
    +*   rc-cec                   cec
    +*   rc-cinergy-1400          cinergy_1400
    +*   rc-cinergy               cinergy
    +*   rc-delock-61959          delock_61959
    +*   rc-dib0700-nec           dib0700_nec
    +*   rc-dib0700-rc5           dib0700_rc5
    +*   rc-digitalnow-tinytwin   digitalnow_tinytwin
    +*   rc-digittrade            digittrade
    +*   rc-dm1105-nec            dm1105_nec
    +*   rc-dntv-live-dvb-t       dntv_live_dvb_t
    +*   rc-dntv-live-dvbt-pro    dntv_live_dvbt_pro
    +*   rc-dtt200u               dtt200u
    +*   rc-dvbsky                dvbsky
    +*   rc-em-terratec           em_terratec
    +*   rc-encore-enltv-fm53     encore_enltv_fm53
    +*   rc-encore-enltv          encore_enltv
    +*   rc-encore-enltv2         encore_enltv2
    +*   rc-evga-indtube          evga_indtube
    +*   rc-eztv                  eztv
    +*   rc-flydvb                flydvb
    +*   rc-flyvideo              flyvideo
    +*   rc-fusionhdtv-mce        fusionhdtv_mce
    +*   rc-gadmei-rm008z         gadmei_rm008z
    +*   rc-genius-tvgo-a11mce    genius_tvgo_a11mce
    +*   rc-gotview7135           gotview7135
    +*   rc-hauppauge             hauppauge
    +#*  rc-imon-mce              imon_mce
    +#*  rc-imon-pad              imon_pad
    +*   rc-iodata-bctv7e         iodata_bctv7e
    +*   rc-it913x-v1             it913x_v1
    +*   rc-it913x-v2             it913x_v2
    +*   rc-kaiomy                kaiomy
    +*   rc-kworld-315u           kworld_315u
    +*   rc-kworld-pc150u         kworld_pc150u
    +*   rc-kworld-plus-tv-analog kworld_plus_tv_analog
    +*   rc-leadtek-y04g0051      leadtek_y04g0051
    +*   rc-lme2510               lme2510
    +*   rc-manli                 manli
    +*   rc-medion-x10-digitainer medion_x10_digitainer
    +*   rc-medion-x10-or2x       medion_x10_or2x
    +*   rc-medion-x10            medion_x10
    +*   rc-msi-digivox-ii        msi_digivox_ii
    +*   rc-msi-digivox-iii       msi_digivox_iii
    +*   rc-msi-tvanywhere-plus   msi_tvanywhere_plus
    +*   rc-msi-tvanywhere        msi_tvanywhere
    +*   rc-nebula                nebula
    +*   rc-nec-terratec-cinergy-xs nec_terratec_cinergy_xs
    +*   rc-norwood               norwood
    +*   rc-npgtech               npgtech
    +*   rc-pctv-sedna            pctv_sedna
    +*   rc-pinnacle-color        pinnacle_color
    +*   rc-pinnacle-grey         pinnacle_grey
    +*   rc-pinnacle-pctv-hd      pinnacle_pctv_hd
    +*   rc-pixelview-002t        pixelview_002t
    +*   rc-pixelview-mk12        pixelview_mk12
    +*   rc-pixelview-new         pixelview_new
    +*   rc-pixelview             pixelview
    +*   rc-powercolor-real-angel powercolor_real_angel
    +*   rc-proteus-2309          proteus_2309
    +*   rc-purpletv              purpletv
    +*   rc-pv951                 pv951
    +*   rc-real-audio-220-32-keys real_audio_220_32_keys
    +*   rc-reddo                 reddo
    +*   rc-snapstream-firefly    snapstream_firefly
    +*   rc-streamzap             streamzap
    +*   rc-su3000                su3000
    +*   rc-tbs-nec               tbs_nec
    +*   rc-technisat-ts35        technisat_ts35
    +*   rc-technisat-usb2        technisat_usb2
    +*   rc-terratec-cinergy-c-pci terratec_cinergy_c_pci
    +*   rc-terratec-cinergy-s2-hd terratec_cinergy_s2_hd
    +*   rc-terratec-cinergy-xs   terratec_cinergy_xs
    +*   rc-terratec-slim-2       terratec_slim_2
    +*   rc-terratec-slim         terratec_slim
    +*   rc-tevii-nec             tevii_nec
    +*   rc-tivo                  tivo
    +*   rc-total-media-in-hand-02 total_media_in_hand_02
    +*   rc-total-media-in-hand   total_media_in_hand
    +*   rc-trekstor              trekstor
    +*   rc-tt-1500               tt_1500
    +*   rc-twinhan-dtv-cab-ci    twinhan_dtv_cab_ci
    +*   rc-twinhan1027           twinhan_vp1027_dvbs
    +*   rc-videomate-k100        videomate_k100
    +*   rc-videomate-s350        videomate_s350
    +*   rc-videomate-tv-pvr      videomate_tv_pvr
    +*   rc-winfast-usbii-deluxe  winfast_usbii_deluxe
    +*   rc-winfast               winfast
    +# * *            a800                 # found in a800.c
    +# * *            af9005               # found in af9005-remote.c
    +# * *            cinergyt2            # found in cinergyT2-core.c
    +# * *            dvico_mce            # found in cxusb.c
    +# * *            dvico_portable       # found in cxusb.c
    +# * *            d680_dmb             # found in cxusb.c
    +# * *            dibusb               # found in dibusb-common.c
    +# * *            digitv               # found in digitv.c
    +# * *            megasky              # found in m920x.c
    +# * *            tvwalkerir-kbd-i2c rc-hauppauge            /lib/udev/rc_keymaps/rc-hauppaugetwin         # found in m920x.c
    +# * *            pinnacle310e         # found in m920x.c
    +# * *            haupp                # found in nova-t-usb2.c
    +# * *            opera1               # found in opera1.c
    +# * *            vp702x               # found in vp702x.c
    +# * *            vp7045               # found in vp7045.c
    +
    +# Hauppauge PVR 350
    +ir-kbd-i2c  rc-hauppauge    /lib/udev/rc_keymaps/rc-hauppauge
    +
    +# imon-pad
    +imon        rc-imon-pad /lib/udev/rc_keymaps/rc-imon-pad
    +imon        rc-imon-mce /lib/udev/rc_keymaps/rc-imon-mce
    +
    +# TT-1500/1501
    +*           rc-tt-1500  /lib/udev/rc_keymaps/rc-tt-1500
    +budget_ci   rc-tt-1500  /lib/udev/rc_keymaps/rc-tt-1501
    +
    +# rc-rc6-mce
    +*           rc-rc6-mce  /lib/udev/rc_keymaps/rc-rc6-mce
    +# CIR
    +ite-cir     rc-rc6-mce  /lib/udev/rc_keymaps/rc-rc6-mce
    +nuvoton-cir rc-rc6-mce  /lib/udev/rc_keymaps/rc-rc6-mce
    +
    +# mceusb
    +mceusb      rc-rc6-mce  /lib/udev/rc_keymaps/HOPLOrc6
    +
    +# Skystarhd2
    +mantis_core * /lib/udev/rc_keymaps/skystarhd2
    +
    +# Medion X10
    +ati_remote    rc-medion-x10              /lib/udev/rc_keymaps/rc-medion-x10
    +ati_remote    rc-medion-x10-or2x         /lib/udev/rc_keymaps/rc-medion-x10-or2x
    +ati_remote    rc-medion-x10-digitainer   /lib/udev/rc_keymaps/rc-medion-x10-digitainer
    +
    +
    +
    +
  6. +
+
+
+

7.8.4 files

+
+
+ +
+

7.9 pulseaudio

+
+
+
+

7.9.1 tasks

+
+
+
---
+
+- name: apt | install pulseaudio, pavucontrol and vdr-plugin-pulsecontrol
+  apt:
+    name: '{{ item }}'
+    state: present
+    install_recommends: no
+  with_items:
+    - pulseaudio
+    - pavucontrol
+    - vdr-plugin-pulsecontrol
+
+- name: create /etc/asound.conf with pulseaudio as default device
+  template:
+    src: templates/alsa/asound.conf.j2
+    dest: /etc/asound.conf
+
+
+
+
+
+

7.9.2 templates

+
+
+
# Use PulseAudio by default
+pcm.!default {
+  type pulse
+  fallback "sysdefault"
+  hint {
+    show on
+    description "Default ALSA Output (currently PulseAudio Sound Server)"
+  }
+}
+
+ctl.!default {
+  type pulse
+  fallback "sysdefault"
+}
+
+
+
+
+
+
+

7.10 yavdr-xorg

+
+
+
+

7.10.1 About the GUI session

+
+

+The X-Server is started by using the two systemd units xlogin@.service and x@.service provided by the package xlogin. The former is enabled (and started) for the vdr user - which results (using the default settings for the user vdr with the uid 666) in the activation of xlogin@vdr.service when reaching the graphical.target. +

+ +

+x@vt7.service is started automatically as a dependency of xlogin@vdr.service and starts the X-server. xlogin@vdr.service also starts a systemd user session using user@666.service. +In order to use the keyboard layout configured during installation for the X-Server the script write-x11-keyboard-config reads the keyboard configuration from /etc/default/keyboard when starting x@.service and writes the file /etc/X11/xorg.conf.d/00-keyboard.conf (because systemd for Ubuntu (and Debian) has been patched not to create /etc/X11/xorg.conf.d/00-keyboard.conf according to the localectl settings). +

+ +

+To prevent stopping the X-server when vdr is running, additional dependencies are set up - see the drop-in rules created in /etc/systemd/system/vdr.service.d/. +

+ +

+Basic Services like the session DBus, pulseaudio etc. are started for the default.target of the session. +The openbox autostart script is used to update the systemd session with the needed session variables. It creates a file ~/.session-env which is used as an environment file by vdr.service (so the vdr knows the DISPLAY and can access pulseaudio). +

+ +

+The autostart script then enables all services to be pulled in by yavdr-desktop.target. As the last step yavdr-desktop.target is startet, which results in staring yavdr-frontend.service and additional Units for a second display (openbox and a browser for osd2eb, if available). +

+ +

+In order to achive a clean shutdown of the session, x@t7.service is set as a dependency of the systemd unit instance user@666.service and all processes within the session must be shutdown properly when stopping xlogin@vdr.service. If systemd units are used within the user session, they must stop their process(es) successfully (you should set them up to accept expected exit codes appropriately). The window manager openbox is started using the ~/.xinitrc and stopped using the systemd unit exit-wm.service (which runs on stopping the jobs pulled in by the default.target of the session). +

+
+
+
+

7.10.2 default variables

+
+
+
first_run: False
+xorg_data: {}
+
+
+
+
+
+

7.10.3 tasks

+
+
+
    +
  1. main.yml
    +
    +
    +
    ---
    +# file: roles/yavdr-xorg/tasks/main.yml
    +- import_tasks: setup-xorg.yml
    +  tags: [install,update]
    +- import_tasks: detect-xorg.yml
    +  tags: [xorg.detect,install]
    +- import_tasks: desktop-session.yml
    +  tags: [install,update]
    +
    +
    +
    +
  2. +
  3. setup-xorg.yml
    +
    +
    +
    ---
    +# file: roles/yavdr-xorg/tasks/setup-xorg.yml
    +- name: create directories for systemd drop-in files
    +  file:
    +    dest: '{{ item }}'
    +    state: directory
    +  with_items:
    +    - "/etc/systemd/system/x@.service.d/"
    +    - "/etc/systemd/system/vdr.service.d/"
    +    - "/etc/systemd/system/user@{{ vdr.uid }}.service.d/"
    +    - "/etc/X11/xorg.conf.d/"
    +
    +- name: systemd-drop-in | add dependency to X-server for vdr.service
    +  template:
    +    src: templates/vdr-xorg.conf
    +    dest: /etc/systemd/system/vdr.service.d/vdr-xorg.conf
    +
    +- name: systemd-drop-in | start x@.service before xlogin@.service
    +  template:
    +    src: templates/x@service.d/xlogin.conf.j2
    +    dest: /etc/systemd/system/x@.service.d/xlogin.conf
    +
    +- name: systemd-drop-in | load environment file for vdr.service
    +  template:
    +    src: templates/systemd/vdr-environ.j2
    +    dest: /etc/systemd/system/vdr.service.d/load-environ.conf
    +
    +- name: systemd-drop-in | start vdr.service after network-online.target
    +  template:
    +    src: templates/systemd/network-online.j2
    +    dest: /etc/systemd/system/vdr.service.d/network-online.conf
    +
    +- name: systemd-drop-in | user@{{ vdr.uid }}.service depends on x@vt7.service
    +  template:
    +    src: templates/user@666.service.d/x-dependency.conf.j2
    +    dest: '/etc/systemd/system/user@{{ vdr.uid }}.service.d/x-dependency.conf'
    +
    +- name: vdr-config | start softhddevice detached and set audio to pulseaudio
    +  lineinfile:
    +    path: /etc/vdr/conf.avail/softhddevice.conf
    +    line: '{{ item }}'
    +  with_items:
    +      - '-D'
    +      # - '-a pulse' # do we need this with our existing asound.conf?
    +
    +- name: add a login shell for the user vdr
    +  user:
    +      name: '{{ vdr.user }}'
    +      shell: '/bin/bash'
    +      state: present
    +      uid: '{{ vdr.uid }}'
    +      groups: '{{ vdr.group }}'
    +      append: yes
    +
    +- name: apt | install packages for xorg
    +  apt:
    +    name: '{{ item }}'
    +    state: present
    +  with_items:
    +    - xlogin
    +    - xorg
    +    - xserver-xorg-input-all
    +    - xserver-xorg-video-all
    +    - openbox
    +    - python3-dbus2vdr
    +    - python3-yavdrfrontend
    +    - read-edid
    +    - tmux
    +    - vdr-plugin-desktop
    +    - vdr-plugin-osd2web
    +    - feh
    +    #- yavdr-xorg
    +
    +- name: download yavdr logo
    +  block:
    +    - file:
    +        dest: '/usr/share/yavdr/images'
    +        state: directory
    + 
    +    - get_url:
    +        url: 'https://github.com/yavdr/yavdr-base/raw/master/images/yavdr_logo.png'
    +        dest: '/usr/share/yavdr/images/yavdr_logo.png'
    +
    +- name: command | write keyboard configuration to /etc/X11/xorg.conf.d/00-keyboard.conf
    +  command: write-x11-keyboard-config
    +  args:
    +    creates: /etc/X11/xorg.conf.d/00-keyboard.conf
    +  # NOTE: write-x11-keyboard-config is in the xlogin package
    +  # Ubuntu's systemd is patched, so it does not create the file automatically
    +
    +- name: apt | install desktop programs
    +  apt:
    +    name: '{{ item }}'
    +    state: present
    +  with_items:
    +    - xterm
    +    - firefox
    +    - kiosk-browser
    +
    +
    +
    +
  4. +
  5. detect-xorg.yml
    +
    +
    +
    ---
    +# file: roles/yavdr-xorg/tasks/detect-xorg.yml
    +
    +- name: "expand template for x-verbose@.service"
    +  template:
    +    src: "templates/systemd/system/x-verbose@.service.j2"
    +    dest: "/etc/systemd/system/x-verbose@.service"
    +
    +- name: "expand template for xorg-verbose.conf"
    +  template:
    +    src: "templates/xorg-verbose.conf.j2"
    +    dest: "/etc/X11/xorg-verbose.conf"
    +
    +- name: Stop VDR
    +  systemd:
    +    name: vdr.service
    +    state: stopped
    +    enabled: yes
    +  notify: ['Start VDR']
    +
    +- name: Stop xlogin
    +  systemd:
    +    name: 'xlogin@{{ vdr.user }}.service'
    +    state: stopped
    +  notify: ['Start xlogin']
    +
    +- name: Stop x
    +  systemd:
    +    name: x@vt7.service
    +    state: stopped
    +
    +- name: Workaround for wrong connector names on first run
    +  block:
    +    - name: "wait a little bit before starting x-verbose@vt7.service (needed?)"
    +      wait_for:
    +        timeout: 10
    +    
    +    - name: "start x-verbose@.service"
    +      systemd:
    +          name: "x-verbose@vt7.service"
    +          state: started
    +          enabled: false
    +          masked: false
    +          daemon_reload: true
    +    
    +    - name: "wait a little bit, so X has some time to start up (needed?)"
    +      wait_for:
    +        timeout: 3
    +    
    +    - name: "stop x-verbose@vt7.service"
    +      systemd:
    +        name: "x-verbose@vt7.service"
    +        state: stopped
    +        enabled: false
    +        masked: true
    +  when: first_run
    +
    +- name: "wait a little bit, so X has some time to shut down (needed?)"
    +  wait_for:
    +    timeout: 3
    +
    +- name: "trigger udevadm reload"
    +  command: 'udevadm trigger '
    +
    +- name: "wait a little bit, so udev has some time to reapply rules (needed?)"
    +  wait_for:
    +    timeout: 3
    +
    +- name: "start x-verbose@.service"
    +  systemd:
    +    name: "x-verbose@vt7.service"
    +    state: started
    +    enabled: false
    +    masked: false
    +    daemon_reload: true
    +
    +- name: "wait a little bit, so X has some time to start up (needed?)"
    +  wait_for:
    +    timeout: 3
    +
    +- name: "detect xorg configuration"
    +  action: xrandr_facts
    +
    +- debug:
    +    var: xorg.primary
    +
    +- debug:
    +    var: xorg.secondary
    +  when: xorg.secondary is defined
    +
    +- name: "stop x-verbose@vt7.service"
    +  systemd:
    +    name: "x-verbose@vt7.service"
    +    state: stopped
    +    enabled: false
    +    masked: true
    +
    +- name: "wait a little bit, so X has some time to shut down (needed?)"
    +  wait_for:
    +    timeout: 3
    +
    +- name: save results
    +  block:
    +    - name: write xorg and xrandr variable to xorg_data dictionary
    +    - set_fact:
    +        xorg_data: '{{ xorg_data|combine({item[0]: item[1]}) }}'
    +      with_items:
    +        - ('xorg', xorg)
    +        - ('xrandr', xrandr['Screen 0:'])
    +
    +    - name: write xorg variable to /etc/yavdr/xorg.yml
    +    block:
    +        - file:
    +            state: directory
    +            path: /etc/ansible/facts.d
    +        - copy:
    +            content: '{{ xorg_data | to_nice_json }}'
    +            dest: /etc/ansible/facts.d/xorg.fact
    +  when:
    +    - xrandr is defined
    +    - xorg is defined
    +
    +- name: update xorg and xrandr variable with values from local facts if needed
    +  set_fact:
    +    xorg: '{{ ansible_local.xorg }}'
    +    xrandr: '{{ ansible_local.xrandr }}'
    +  when:
    +    - xrandr is undefined
    +    - xorg is undefined
    +
    +# TODO: expand template for xorg.conf (or snippets)
    +#       with respect for the available graphics card driver
    +#       nvidia, noveau, intel, radeon
    +
    +- name: nvidia related config
    +  block:
    +  - name: create xorg.conf (for nvidia driver)
    +    template:
    +        src: templates/xorg.conf.j2
    +        dest: /etc/X11/xorg.conf
    +        backup: yes
    +  when:
    +    - nvidia_detected
    +
    +
    +
    +
    +
  6. +
  7. desktop-session.yml
    +
    +
    +
    ---
    +# file: roles/yavdr-xorg/tasks/desktop-session.yml
    +
    +- name: create folders for user configuration files
    +  file:
    +    state: directory
    +    dest: '{{ item }}'
    +    mode: '0775'
    +    owner: '{{ vdr.user }}'
    +    group: '{{ vdr.group }}'
    +  with_items:
    +    - '{{ vdr.home }}/.config/systemd/user'
    +    - '{{ vdr.home }}/.config/openbox'
    +    - '{{ vdr.home }}/.config/pulse'
    +
    +- name: expand template for .xinitrc for vdr user
    +  template:
    +      src: 'templates/.xinitrc.j2'
    +      dest: '{{ vdr.home }}/.xinitrc'
    +      mode: 0755
    +      owner: '{{ vdr.user }}'
    +      group: '{{ vdr.group }}'
    +
    +- name: "expand template for vdr's .Xresources"
    +  template:
    +      src: 'templates/.Xresources.j2'
    +      dest: '{{ vdr.home }}/.Xresources'
    +      mode: 0644
    +      owner: '{{ vdr.user }}'
    +      group: '{{ vdr.group }}'
    +
    +- name: expand template for openbox autostart
    +  template:
    +      src: 'templates/openbox/autostart.j2'
    +      dest: '{{ vdr.home }}/.config/openbox/autostart'
    +      mode: 0755
    +      owner: '{{ vdr.user }}'
    +      group: '{{ vdr.group }}'
    +
    +- name: expand rc.xml for openbox
    +  template:
    +      src: 'templates/openbox/rc.xml.j2'
    +      dest: '{{ vdr.home }}/.config/openbox/rc.xml'
    +      mode: 0644
    +      owner: '{{ vdr.user }}'
    +      group: '{{ vdr.group }}'
    +
    +- name: create yavdr-desktop.target for the user session
    +  template:
    +      src: 'templates/systemd/user/yavdr-desktop.target.j2'
    +      dest: '{{ vdr.home }}/.config/systemd/user/yavdr-desktop.target'
    +      mode: 0644
    +      owner: '{{ vdr.user }}'
    +      group: '{{ vdr.group }}'
    +
    +- name: disable pulseaudio autospawning
    +  lineinfile:
    +    path: '{{ vdr.home }}/.config/pulse/client.conf'
    +    line: 'autospawn = no'
    +    create: yes
    +    state: present
    +    owner: '{{ vdr.user }}'
    +    group: '{{ vdr.group }}'
    +
    +- name: create tmux.service for the session
    +  template:
    +    src: roles/yavdr-xorg/templates/systemd/user/tmux.service.j2
    +    dest: '{{ vdr.home }}/.config/systemd/user/tmux.service'
    +
    +- name: create wm-exit.service for the session
    +  template:
    +    src: roles/yavdr-xorg/templates/systemd/user/wm-exit.service.j2
    +    dest: '{{ vdr.home }}/.config/systemd/user/wm-exit.service'
    +
    +- name: create detect-second-display.service for the session
    +  template:
    +    src: templates/systemd/user/detect-second-display.service.j2
    +    dest: '{{ vdr.home }}/.config/systemd/user/detect-second-display.service'
    +
    +- name: create openbox-second.service for the session
    +  template:
    +    src: templates/systemd/user/openbox-second.service.j2
    +    dest: '{{ vdr.home }}/.config/systemd/user/openbox-second.service'
    +
    +- name: create osd2web.service for the session
    +  template:
    +    src: templates/systemd/user/osd2web.service.j2
    +    dest: '{{ vdr.home }}/.config/systemd/user/osd2web.service'
    +
    +- name: create irexec configuration for the session
    +  block:
    +    - template:
    +        src: templates/systemd/user/irexec.service.j2
    +        dest: '{{ vdr.home }}/.config/systemd/user/irexec.service'
    +    - template:
    +        src: templates/.lircrc.j2
    +        dest: '{{ vdr.home }}/.lircrc'
    +
    +- name: link /usr/bin/start-desktop to /var/lib/vdr/plugins/desktop/starter
    +  file:
    +    src: /usr/bin/start-desktop
    +    dest: /var/lib/vdr/plugins/desktop/starter
    +    state: link
    +  
    +- name: enable and start xlogin for the vdr user
    +  systemd:
    +    daemon_reload: yes
    +    name: 'xlogin@{{ vdr.user }}'
    +    enabled: yes
    +    state: started
    +
    +
    +
    +
  8. +
+
+
+

7.10.4 templates

+
+
+
    +
  1. xorg
    +
      +
    1. x-verbose@.service
      +
      +
      +
      # file: roles/yavdr-xorg/templates/systemd/system/x-verbose@.service.j2
      +[Unit]
      +Description=X with verbose logging on %I
      +Wants=graphical.target
      +Before=graphical.target
      +
      +[Service]
      +Type=forking
      +ExecStart=/usr/bin/x-daemon -logverbose 6 -noreset %I -config /etc/X11/xorg-verbose.conf
      +
      +
      +
      +
    2. +
    3. Drop-in snippet for x@.service
      +
      +
      +
      [Unit]
      +Before=xlogin@{{ vdr.user }}.service
      +
      +
      + +
      +
      [Unit]
      +Wants=x@vt7.service
      +After=x@vt7.service
      +
      +[Service]
      +TimeoutStopSec=20
      +KillMode=mixed
      +
      +
      +
      +
    4. + +
    5. Drop-in snippet for vdr.service
      +
      +
      +
      {{ ansible_managed | comment }}
      +[Unit]
      +After=x@vt7.service
      +Wants=x@vt7.service
      +#BindsTo=x@vt7.service
      +
      +
      +
      +
    6. +
    7. .xinitrc
      +
      +
      +
      #!/bin/bash
      +{{ ansible_managed | comment }}
      +exec openbox-session
      +
      +
      +
      +
    8. +
    9. xorg.conf
      +
      +
      +
      Section "Device"
      +        Identifier "nvidia"
      +        Driver  "nvidia"
      +        Option  "NoLogo"              "true"
      +        Option  "DynamicTwinView"     "true"
      +        Option  "NoFlip"              "false"
      +#        Option  "FlatPanelProperties" "Scaling = Native"
      +#        Option  "ModeValidation"      "NoVesaModes, NoXServerModes"
      +#        Option  "ModeDebug"           "true"
      +#        Option  "HWCursor"            "false"
      +EndSection
      +
      +Section "Screen"
      +        Identifier      "screen"
      +        Device          "nvidia"
      +EndSection
      +
      +Section "Extensions"
      +        Option  "Composite"           "false"
      +EndSection
      +
      +
      +
      +
      {{ ansible_managed | comment }}
      +
      +Section "ServerLayout"
      +    Identifier     "Layout0"
      +    Screen         0  "Screen0" 0 0
      +{% if xorg.secondary is defined %}
      +    Screen         1  "Screen1" RightOf "Screen0"
      +{% endif %}
      +    #InputDevice    "Keyboard0" "CoreKeyboard"
      +    #InputDevice    "Mouse0" "CorePointer"
      +    Option         "Xinerama" "0"
      +EndSection
      +
      +Section "InputClass"
      +    Identifier "exclude eventlircd devices"
      +    MatchTag   "eventlircd"
      +    Option     "Ignore"    "True"
      +EndSection
      +
      +Section "Monitor"
      +    Identifier     "Monitor0"
      +    VendorName     "{{ xorg.primary.vendor }}"
      +    ModelName      "{{ xorg.primary.model }}"
      +    Option         "DPMS"
      +    Option         "ExactModeTimingsDVI" "True"
      +EndSection
      +
      +Section "Device"
      +    Identifier     "Device0"
      +    Driver         "nvidia"
      +    VendorName     "NVIDIA Corporation"
      +    Option         "NoLogo"              "true"
      +{% if xorg.primary.bus_id is defined %}
      +    BoardName      "{{ xorg.primary.gpu_name }}"
      +    BusID          "{{ xorg.primary.bus_id }}"
      +{% else %}
      +    BoardName      "Unknown"
      +{% endif %}
      +    Screen          0
      +EndSection
      +
      +Section "Screen"
      +    Identifier     "Screen0"
      +    Device         "Device0"
      +    Monitor        "Monitor0"
      +    DefaultDepth    24
      +    Option         "nvidiaXineramaInfoOrder" "{{ xorg.primary.connector }}"
      +    Option         "ConnectedMonitor" "{{ xorg.primary.connector }}{% if xorg.secondary is defined %}, {{ xorg.secondary.connector }}{% endif %}"
      +    Option         "UseDisplayDevice" "{{ xorg.primary.connector }}"
      +    Option         "CustomEDID" "{{ xorg.primary.connector }}:/etc/X11/edid.{{ xorg.primary.connector }}.bin"
      +    Option         "metamodes" "{{ xorg.primary.connector }}: {{ xorg.primary.mode }} +0+0 {ForceCompositionPipeline=On, ForceFullCompositionPipeline=On}"
      +    Option         "AllowIndirectGLXProtocol" "off"
      +    Option         "TripleBuffer" "on"
      +    Option         "SLI" "Off"
      +    Option         "MultiGPU" "Off"
      +    Option         "BaseMosaic" "off"
      +    SubSection     "Display"
      +        Depth       24
      +    EndSubSection
      +EndSection
      +
      +{% if xorg.secondary is defined %}
      +Section "Device"
      +    Identifier     "Device1"
      +    Driver         "nvidia"
      +    VendorName     "NVIDIA Corporation"
      +    Option  "NoLogo"              "true"
      +{% if xorg.secondary.bus_id is defined %}
      +    BoardName      "{{ xorg.primary.gpu_name }}"
      +    BusID          "{{ xorg.primary.bus_id }}"
      +{% else %}
      +    BoardName      "Unknown"
      +{% endif %}
      +    Screen          1
      +EndSection
      +
      +Section "Monitor"
      +    Identifier     "Monitor1"
      +    VendorName     "{{ xorg.secondary.vendor }}"
      +    ModelName      "{{ xorg.secondary.model }}"
      +EndSection
      +
      +Section "Screen"
      +    Identifier     "Screen1"
      +    Device         "Device1"
      +    Monitor        "Monitor1"
      +    DefaultDepth    24
      +    Option         "nvidiaXineramaInfoOrder" "{{ xorg.secondary.connector }}"
      +    Option         "ConnectedMonitor" "{{ xorg.secondary.connector }}"
      +    Option         "UseDisplayDevice" "{{ xorg.secondary.connector }}"
      +    Option         "CustomEDID" "{{ xorg.secondary.connector }}:/etc/X11/edid.{{ xorg.secondary.connector }}.bin"
      +    Option         "metamodes" "{{ xorg.secondary.connector }}: {{ xorg.secondary.mode }} +0+0 {ForceCompositionPipeline=On, ForceFullCompositionPipeline=On}"
      +    Option         "AllowIndirectGLXProtocol" "off"
      +    Option         "TripleBuffer" "on"
      +    Option         "SLI" "Off"
      +    Option         "MultiGPU" "Off"
      +    Option         "BaseMosaic" "off"
      +    SubSection     "Display"
      +        Depth       24
      +    EndSubSection
      +EndSection
      +{% endif %}
      +
      +
      + +
      +
      {{ ansible_managed | comment }}
      +
      +Section "ServerLayout"
      +    Identifier     "Layout0"
      +    Screen      0  "Screen0"
      +    {% if xorg.best_tv_mode.secondary is defined %}
      +    Screen      1  "Screen1" RightOf "Screen0"
      +    {% endif %}
      +    InputDevice    "Keyboard0" "CoreKeyboard"
      +    InputDevice    "Mouse0" "CorePointer"
      +EndSection
      +
      +Section "InputDevice"
      +    # generated from default
      +    Identifier     "Mouse0"
      +    Driver         "mouse"
      +    Option         "Protocol" "auto"
      +    Option         "Device" "/dev/psaux"
      +    Option         "Emulate3Buttons" "no"
      +    Option         "ZAxisMapping" "4 5"
      +EndSection
      +
      +# ignore devices with eventlircd tag 
      +# ENV{ID_INPUT.tags}+="eventlircd"
      +# must be set by an udev rule
      +Section "InputClass"
      +    Identifier "ignore eventlircd devices"
      +    MatchTag "eventlircd"
      +    Option "Ignore" "True"
      +EndSection
      +
      +
      +
      +Section "InputDevice"
      +    # generated from default
      +    Identifier     "Keyboard0"
      +    Driver         "kbd"
      +EndSection
      +
      +
      +Section "Monitor"
      +    Identifier     "Monitor0"
      +    VendorName     "Unknown"
      +    ModelName      "Unknown"
      +{# TODO: VGA2SCART support (if needed)
      +{% if system.x11.display.0.default == "VGA2Scart_4_3" or system.x11.display.0.default == "VGA2Scart_16_9" %}
      +    HorizSync       14-17
      +    VertRefresh     49-61
      +    {% if system.x11.display.0.default == "VGA2Scart_4_3" %}
      +    Modeline "VGA2Scart_4_3" 13.875 720 744 808 888 576 580 585 625 -HSync -Vsync interlace
      +    {% elif system.x11.display.0.default == "VGA2Scart_16_9" %}
      +    Modeline "VGA2Scart_16_9" 19 1024 1032 1120 1216 576 581 586 625 -Hsync -Vsync interlace
      +    {% endif %}
      +{% endif %}
      +#}
      +    Option         "DPMS"
      +    Option         "ExactModeTimingsDVI" "True"
      +EndSection
      +
      +
      +{% if xrandr.best_tv_mode.secondary is defined %}
      +Section "Monitor"
      +    Identifier     "Monitor1"
      +    VendorName     "Unknown"
      +    ModelName      "Unknown"
      +{#
      +{% if system.x11.display.1.default in ("VGA2Scart_4_3",  "VGA2Scart_16_9") %}
      +    HorizSync       14-17
      +    VertRefresh     49-61
      +    {% if system.x11.display.1.default == "VGA2Scart_4_3" %}
      +    Modeline "VGA2Scart_4_3" 13.875 720 744 808 888 576 580 585 625 -HSync -Vsync interlace
      +    {% elif system.x11.display.1.default == "VGA2Scart_16_9" %}
      +    Modeline "VGA2Scart_16_9" 19 1024 1032 1120 1216 576 581 586 625 -Hsync -Vsync interlace
      +    {% endif %}
      +    Option         "DPMS"
      +    Option         "ExactModeTimingsDVI" "True"
      +{% endif %}
      +#}
      +EndSection
      +{% endif %}
      +
      +Section "Device"
      +    Identifier     "Device0"
      +{% if system.hardware.nvidia.detected %}
      +    Driver         "nvidia"
      +    VendorName     "NVIDIA Corporation"
      +{% endif %}
      +    Screen          0
      +    Option         "DPI" "100x100"
      +{% if system.hardware.nvidia.busid is defined and system.hardware.busid %}
      +    BusID          "PCI: {{ system.hardware.nvidia.busid }}"
      +{% endif %}
      +    Option         "NoLogo" "True"
      +    Option         "UseEvents" "True"
      +    Option         "TripleBuffer" "False"
      +    Option         "AddARGBGLXVisuals" "True"
      +    Option         "TwinView" "0"
      +    Option         "DynamicTwinView" "0"
      +    Option         "OnDemandVBlankinterrupts" "on"
      +    Option         "FlatPanelProperties" "Scaling = Native"
      +EndSection
      +
      +{% if xrandr.best_tv_mode.secondary is defined %}
      +Section "Device"
      +    Identifier     "Device1"
      +    {% if system.hardware.nvidia.detected %}
      +    Driver         "nvidia"
      +    VendorName     "NVIDIA Corporation"
      +    {% endif %}
      +    Screen          1
      +    {% if system.hardware.nvidia.busid is defined and system.hardware.nvidia.busid %}
      +    BusID          "PCI: {{ system.hardware.nvidia.busid }}"
      +    {% endif %}
      +    Option         "NoLogo" "True"
      +    Option         "UseEvents" "True"
      +    Option         "TripleBuffer" "False"
      +    Option         "AddARGBGLXVisuals" "True"
      +    Option         "TwinView" "0"
      +    Option         "DynamicTwinView" "0"
      +EndSection
      +{% endif %}
      +
      +
      +Section "Screen"
      +    Identifier     "Screen0"
      +    Device         "Device0"
      +    Monitor        "Monitor0"
      +    DefaultDepth    24
      +    SubSection     "Display"
      +        Depth       24
      +{% if xrandr.best_tv_mode.primary is defined %}
      +        Modes      "{{ xrandr.best_tv_mode.primary.mode }}"{#{% for mode in xrandr %}{% if mode != system.x11.display.0.default %} "{{ mode }}"{% endif %}{% endfor %}#} nvidia-auto-select
      +
      +{% elif system.hardware.nvidia.detected == 1 %}
      +        Modes      "nvidia-auto-select"
      +{% endif %}
      +    EndSubSection
      +{% if system.x11.display.0.default or system.x11.default %}
      +    {% if system.x11.display.0.device is definded and system.x11.display.0.device %}
      +    Option         "ConnectedMonitor" {{ system.x11.display.0.device }}
      +    {% else %}
      +    Option         "ConnectedMonitor" {{ system.x11.default }}
      +    {% endif %}
      +    #     Option         "ConnectedMonitor" "<?cs if:(?system.x11.display.0.device) ?><?cs call:fix_display_name(system.x11.display.0.device) ?><?cs else ?><?cs var:system.x11.default ?><?cs /if ?><?cs if:(?system.x11.dualhead.enabled && system.x11.dualhead.enabled == 1) ?>, <?cs call:fix_display_name(system.x11.display.1.device) ?><?cs /if ?>"
      +    #Option         "ConnectedMonitor"
      +    "<?cs if:(?system.x11.display.0.device) ?>
      +          <?cs call:fix_display_name(system.x11.display.0.device) ?>
      +     <?cs else ?>
      +          <?cs var:system.x11.default ?>
      +     <?cs /if ?>
      +     <?cs if:(?system.x11.dualhead.enabled && system.x11.dualhead.enabled == 1) ?>, <?cs call:fix_display_name(system.x11.display.1.device) ?><?cs /if ?>"
      +#     Option         "UseDisplayDevice" "<?cs if:(?system.x11.display.0.device) ?><?cs call:fix_display_name(system.x11.display.0.device) ?><?cs else ?><?cs var:system.x11.default ?><?cs /if ?>"
      +# <?cs /if ?>
      +# <?cs if:(?system.hardware.nvidia.0.edid && system.hardware.nvidia.0.edid == "1") ?>
      +#     Option         "CustomEDID" "<?cs call:fix_display_name(system.x11.display.0.device) ?>:/etc/X11/edid.0.yavdr"
      +# <?cs /if ?>
      +# <?cs if:(system.hardware.nvidia.detected == 1 && ?system.x11.display.0.device) ?>
      +#     Option          "MetaModes" "<?cs call:fix_display_name(system.x11.display.0.device) ?>: <?cs var:system.x11.display.0.default ?> { ViewPortIn=<?cs var:system.x11.display.0.viewport.in.x ?>x<?cs var:system.x11.display.0.viewport.in.y ?>, ViewPortOut=<?cs var:system.x11.display.0.viewport.out.x ?>x<?cs var:system.x11.display.0.viewport.out.y ?>+<?cs var:system.x11.display.0.viewport.out.plusx ?>+<?cs var:system.x11.display.0.viewport.out.plusy ?> }"
      +# <?cs each:mode = system.x11.display.0.mode ?><?cs if:(mode != system.x11.display.0.default) ?>
      +#     Option          "MetaModes" "<?cs call:fix_display_name(system.x11.display.0.device) ?>: <?cs var:mode ?> { ViewPortIn=<?cs var:system.x11.display.0.viewport.in.x ?>x<?cs var:system.x11.display.0.viewport.in.y ?>, ViewPortOut=<?cs var:system.x11.display.0.viewport.out.x ?>x<?cs var:system.x11.display.0.viewport.out.y ?>+<?cs var:system.x11.display.0.viewport.out.plusx ?>+<?cs var:system.x11.display.0.viewport.out.plusy ?> }"<?cs /if ?><?cs /each ?> 
      +{% endif %}
      +EndSection
      +
      +{% if system.x11.dualhead.enabled == "1" %}
      +Section "Screen"
      +
      +     Identifier     "Screen1"
      +     Device         "Device1"
      +     Monitor        "Monitor1"
      +     DefaultDepth    24
      +     SubSection     "Display"
      +         Depth       24
      +{% if system.x11.display.0.default is defined and system.x11.display.0.default %}
      +         Modes      "{{ system.x11.display.1.default }}"{% for mode in system.x11.display.1.mode %}{% if mode != system.x11.display.1.default %} "{{ mode }}"{% endif %}{% endfor %}
      +
      +{% elif system.hardware.nvidia.detected == "1" %}
      +         Modes      "nvidia-auto-select"
      +{% endif %}
      +      EndSubSection
      +
      +# <?cs if:(?system.x11.display.1.default && system.x11.display.1.default != "" && system.x11.display.1.default != "disabled") ?>
      +#     Option         "UseDisplayDevice" "<?cs call:fix_display_name(system.x11.display.1.device) ?>"
      +# <?cs /if ?>
      +# <?cs if:(?system.hardware.nvidia.1.edid && system.hardware.nvidia.1.edid == "1") ?>
      +#     Option         "CustomEDID" "<?cs call:fix_display_name(system.x11.display.1.device) ?>:/etc/X11/edid.1.yavdr"
      +# <?cs /if ?>
      +# <?cs if:(system.hardware.nvidia.detected == 1 && ?system.x11.display.1.device) ?>
      +#     Option          "MetaModes" "<?cs call:fix_display_name(system.x11.display.1.device) ?>: <?cs var:system.x11.display.1.default ?> { ViewPortIn=<?cs var:system.x11.display.1.viewport.in.x ?>x<?cs var:system.x11.display.1.viewport.in.y ?>, ViewPortOut=<?cs var:system.x11.display.1.viewport.out.x ?>x<?cs var:system.x11.display.1.viewport.out.y ?>+<?cs var:system.x11.display.1.viewport.out.plusx ?>+<?cs var:system.x11.display.1.viewport.out.plusy ?> }"
      +# <?cs each:mode = system.x11.display.1.mode ?><?cs if:(mode != system.x11.display.1.default) ?>
      +#     Option          "MetaModes" "<?cs call:fix_display_name(system.x11.display.1.device) ?>: <?cs var:mode ?> { ViewPortIn=<?cs var:system.x11.display.1.viewport.in.x ?>x<?cs var:system.x11.display.1.viewport.in.y ?>, ViewPortOut=<?cs var:system.x11.display.1.viewport.out.x ?>x<?cs var:system.x11.display.1.viewport.out.y ?>+<?cs var:system.x11.display.1.viewport.out.plusx ?>+<?cs var:system.x11.display.1.viewport.out.plusy ?> }"<?cs /if ?><?cs /each ?>
      +# <?cs /if ?>
      +EndSection
      +{% endif %}
      +
      +
      +
      +
    10. +
    11. .Xresources
      +
      +
      +
      xterm*background: Black
      +xterm*foreground: grey
      +XTerm*locale: true
      +XTerm*metaSendsEscape: true
      +XTerm*eightBitInput: false
      +XTerm*backarrowKey: false
      +XTerm*ttyModes: erase ^?
      +Xterm*saveLines: 4096
      +XTerm.vt100.metaSendsEscape: true
      +XTerm.vt100.geometry: 80x32
      +XTerm.vt100.renderFont: true
      +xterm*faceName: xft:DejaVu Sans Mono
      +xterm*faceSize: 14
      +xterm*renderFont: true
      +XTerm.vt100.faceName: xft:DejaVu Sans Mono:size=12:antialias=false
      +XTerm.vt100.font: 7x13
      +
      +
      +
      +
    12. +
    +
  2. +
  3. vdr
    +
    +
    +
    [Service]
    +Environment=XDG_RUNTIME_DIR=/run/user/{{ vdr.uid }}/
    +EnvironmentFile=-/var/lib/vdr/.session-env
    +
    +
    + +
    +
    [Unit]
    +After=network-online.target
    +
    +
    +
    +
  4. +
  5. Systemd User Session
    +
      +
    1. yavdr-desktop.target
      +
      +
      +
      [Unit]
      +Description=yaVDR Desktop
      +Requires=default.target
      +After=default.target pulseaudio.service
      +Wants=dbus.service pulseaudio.service
      +AllowIsolate=yes
      +
      +
      +
      +
    2. + +
    3. detect-second-display
      +
      +
      +
      [Unit]
      +Description=Detect second DISPLAY using xrandr
      +
      +[Service]
      +Type=oneshot
      +ExecStart=/bin/bash -c 'export DISPLAY=$DISPLAY.1; xrandr -q | grep "connected" && echo "DISPLAY=$DISPLAY" > ~/.second_display || rm -f ~/.second_display'
      +
      +[Install]
      +WantedBy=yavdr-desktop.target
      +
      +
      +
      +
    4. +
    5. openbox-second.service
      +
      +
      +
      [Unit]
      +Description=Start openbox on the second DISPLAY if it exists
      +After=detect-second-display.service
      +Wants=detect-second-display.service
      +Before=yavdr-frontend.service
      +ConditionFileNotEmpty=%h/.second_display
      +
      +[Service]
      +PassEnvironment=XDG_RUNTIME_DIR DBUS_SESSION_BUS_ADDRESS
      +EnvironmentFile=%h/.second_display
      +ExecStart=/usr/bin/openbox --config-file %h/.config/openbox/rc.xml
      +ExecStartPost=/bin/bash %h/.fehbg
      +
      +[Install]
      +WantedBy=yavdr-desktop.target
      +
      +
      +
      +
    6. +
    7. osd2web.service
      +
      +
      +
      [Unit]
      +Description=Start a kiosk browser on the second DISPLAY if it exists
      +After=detect-second-display.service openbox-second.service
      +Wants=detect-second-display.service openbox-second.service
      +ConditionFileNotEmpty=%h/.second_display
      +
      +[Service]
      +EnvironmentFile=%h/.second_display
      +PassEnvironment=XDG_RUNTIME_DIR DBUS_SESSION_BUS_ADDRESS
      +ExecStart=/usr/bin/on_vdr -o -c 'kiosk-browser "http://localhost:4444/skins/horchiTft/index.html?theme=bluecd&onlyView=1"'
      +KillSignal=SIGINT
      +
      +[Install]
      +WantedBy=yavdr-desktop.target
      +
      +
      +
      +
    8. +
    9. tmux.service
      +
      +
      +
      [Unit]
      +Description=Start tmux in detached session
      +
      +[Service]
      +EnvironmentFile=-%h/.session-env
      +Type=forking
      +ExecStart=/usr/bin/tmux new-session -s use-session -d
      +ExecStop=/usr/bin/tmux kill-session -t %u
      +Restart=always
      +
      +[Install]
      +WantedBy=default.target
      +
      +
      +
      +
    10. +
    11. wm-exit.service
      +
      +
      +
      [Unit]
      +Description=exit window manager gracefully
      +
      +[Service]
      +ExecStart=/bin/true
      +ExecStop=/usr/bin/openbox --exit
      +RemainAfterExit=True
      +
      +[Install]
      +WantedBy=default.target
      +
      +
      +
      +
    12. +
    +
  6. + +
  7. irexec
    +
    +

    +irexec.service starts irexec for the user session +

    +
    +
    [Unit]
    +Description=LIRC command handler
    +
    +[Service]
    +Type=simple
    +ExecStart=/usr/bin/irexec %h/.lircrc
    +
    +[Install]
    +WantedBy=yavdr-desktop.target
    +
    +
    +

    +~/.lircrc contains the irexec configuration +

    +
    +
    begin
    +    prog = irexec
    +    button = KEY_HOME
    +    config = frontend-dbus-send switchbetween kodi vdr
    +end
    +
    +
    +
    +
  8. +
  9. openbox
    +
      +
    1. autostart
      +
      +
      +
      # forward environment variables to an environment file and the systemd user session
      +env | grep "DISPLAY\|DBUS_SESSION_BUS_ADDRESS\|XDG_RUNTIME_DIR" > ~/.session-env
      +systemctl --user import-environment DISPLAY XAUTHORITY XDG_RUNTIME_DIR DBUS_SESSION_BUS_ADDRESS
      +
      +feh --bg-center "/usr/share/yavdr/images/yavdr_logo.png"
      +
      +enabled_services=(
      +    "tmux.service" "detect-second-display.service"
      +    "openbox-second.service" "osd2web.service"
      +    "yavdr-frontend.service" "pulseaudio.socket"
      +    "pulseaudio.service" "wm-exit.service" "irexec.service")
      +disabled_services=()
      +
      +# enable configured services for the user session
      +for service in "${enabled_services[@]}"; do
      +  systemctl --user enable "$service"
      +done
      +
      +# disable unwanted services for the user session
      +for service in "${disabled_services[@]}"; do
      +  systemctl --user disable "$service"
      +done
      +
      +if which dbus-update-activation-environment >/dev/null 2>&1; then
      +        dbus-update-activation-environment DISPLAY XAUTHORITY XDG_RUNTIME_DIR
      +fi
      +
      +# start systemd units for the yavdr user session
      +systemctl --user isolate yavdr-desktop.target
      +
      +
      +
      +
    2. +
    3. rc.xml
      +
      +
      +
      <?xml version="1.0" encoding="UTF-8"?>
      +<openbox_config xmlns="http://openbox.org/3.4/rc" xmlns:xi="http://www.w3.org/2001/XInclude">
      +<!-- Do not edit this file, it will be overwritten on install.
      +        Copy the file to $HOME/.config/openbox/ instead. -->
      +  <resistance>
      +    <strength>10</strength>
      +    <screen_edge_strength>20</screen_edge_strength>
      +  </resistance>
      +  <focus>
      +    <focusNew>yes</focusNew>
      +    <!-- always try to focus new windows when they appear. other rules do
      +       apply -->
      +    <followMouse>no</followMouse>
      +    <!-- move focus to a window when you move the mouse into it -->
      +    <focusLast>yes</focusLast>
      +    <!-- focus the last used window when changing desktops, instead of the one
      +       under the mouse pointer. when followMouse is enabled -->
      +    <underMouse>no</underMouse>
      +    <!-- move focus under the mouse, even when the mouse is not moving -->
      +    <focusDelay>200</focusDelay>
      +    <!-- when followMouse is enabled, the mouse must be inside the window for
      +       this many milliseconds (1000 = 1 sec) before moving focus to it -->
      +    <raiseOnFocus>no</raiseOnFocus>
      +    <!-- when followMouse is enabled, and a window is given focus by moving the
      +       mouse into it, also raise the window -->
      +  </focus>
      +  <placement>
      +    <policy>Smart</policy>
      +    <!-- 'Smart' or 'UnderMouse' -->
      +    <center>yes</center>
      +    <!-- whether to place windows in the center of the free area found or
      +       the top left corner -->
      +    <monitor>Active</monitor>
      +    <!-- with Smart placement on a multi-monitor system, try to place new windows
      +       on: 'Any' - any monitor, 'Mouse' - where the mouse is, 'Active' - where
      +       the active window is, 'Primary' - only on the primary monitor -->
      +    <primaryMonitor>Active</primaryMonitor>
      +    <!-- The monitor where Openbox should place popup dialogs such as the
      +       focus cycling popup, or the desktop switch popup.  It can be an index
      +       from 1, specifying a particular monitor.  Or it can be one of the
      +       following: 'Mouse' - where the mouse is, or
      +                  'Active' - where the active window is -->
      +  </placement>
      +  <theme>
      +    <name>Onyx</name>
      +    <titleLayout>NLIMC</titleLayout>
      +    <!--
      +      available characters are NDSLIMC, each can occur at most once.
      +      N: window icon
      +      L: window label (AKA title).
      +      I: iconify
      +      M: maximize
      +      C: close
      +      S: shade (roll up/down)
      +      D: omnipresent (on all desktops).
      +  -->
      +    <keepBorder>no</keepBorder>
      +    <animateIconify>yes</animateIconify>
      +    <font place="ActiveWindow">
      +      <name>sans</name>
      +      <size>8</size>
      +      <!-- font size in points -->
      +      <weight>bold</weight>
      +      <!-- 'bold' or 'normal' -->
      +      <slant>normal</slant>
      +      <!-- 'italic' or 'normal' -->
      +    </font>
      +    <font place="InactiveWindow">
      +      <name>sans</name>
      +      <size>8</size>
      +      <!-- font size in points -->
      +      <weight>bold</weight>
      +      <!-- 'bold' or 'normal' -->
      +      <slant>normal</slant>
      +      <!-- 'italic' or 'normal' -->
      +    </font>
      +    <font place="MenuHeader">
      +      <name>sans</name>
      +      <size>9</size>
      +      <!-- font size in points -->
      +      <weight>normal</weight>
      +      <!-- 'bold' or 'normal' -->
      +      <slant>normal</slant>
      +      <!-- 'italic' or 'normal' -->
      +    </font>
      +    <font place="MenuItem">
      +      <name>sans</name>
      +      <size>9</size>
      +      <!-- font size in points -->
      +      <weight>normal</weight>
      +      <!-- 'bold' or 'normal' -->
      +      <slant>normal</slant>
      +      <!-- 'italic' or 'normal' -->
      +    </font>
      +    <font place="ActiveOnScreenDisplay">
      +      <name>sans</name>
      +      <size>9</size>
      +      <!-- font size in points -->
      +      <weight>bold</weight>
      +      <!-- 'bold' or 'normal' -->
      +      <slant>normal</slant>
      +      <!-- 'italic' or 'normal' -->
      +    </font>
      +    <font place="InactiveOnScreenDisplay">
      +      <name>sans</name>
      +      <size>9</size>
      +      <!-- font size in points -->
      +      <weight>bold</weight>
      +      <!-- 'bold' or 'normal' -->
      +      <slant>normal</slant>
      +      <!-- 'italic' or 'normal' -->
      +    </font>
      +  </theme>
      +  <desktops>
      +    <!-- this stuff is only used at startup, pagers allow you to change them
      +       during a session
      +
      +       these are default values to use when other ones are not already set
      +       by other applications, or saved in your session
      +
      +       use obconf if you want to change these without having to log out
      +       and back in -->
      +    <number>2</number>
      +    <firstdesk>1</firstdesk>
      +    <names>
      +      <!-- set names up here if you want to, like this:
      +    <name>desktop 1</name>
      +    <name>desktop 2</name>
      +    -->
      +    </names>
      +    <popupTime>875</popupTime>
      +    <!-- The number of milliseconds to show the popup for when switching
      +       desktops.  Set this to 0 to disable the popup. -->
      +  </desktops>
      +  <resize>
      +    <drawContents>yes</drawContents>
      +    <popupShow>Nonpixel</popupShow>
      +    <!-- 'Always', 'Never', or 'Nonpixel' (xterms and such) -->
      +    <popupPosition>Center</popupPosition>
      +    <!-- 'Center', 'Top', or 'Fixed' -->
      +    <popupFixedPosition>
      +      <!-- these are used if popupPosition is set to 'Fixed' -->
      +      <x>10</x>
      +      <!-- positive number for distance from left edge, negative number for
      +         distance from right edge, or 'Center' -->
      +      <y>10</y>
      +      <!-- positive number for distance from top edge, negative number for
      +         distance from bottom edge, or 'Center' -->
      +    </popupFixedPosition>
      +  </resize>
      +  <!-- You can reserve a portion of your screen where windows will not cover when
      +     they are maximized, or when they are initially placed.
      +     Many programs reserve space automatically, but you can use this in other
      +     cases. -->
      +  <margins>
      +    <top>0</top>
      +    <bottom>0</bottom>
      +    <left>0</left>
      +    <right>0</right>
      +  </margins>
      +  <dock>
      +    <position>TopLeft</position>
      +    <!-- (Top|Bottom)(Left|Right|)|Top|Bottom|Left|Right|Floating -->
      +    <floatingX>0</floatingX>
      +    <floatingY>0</floatingY>
      +    <noStrut>no</noStrut>
      +    <stacking>Above</stacking>
      +    <!-- 'Above', 'Normal', or 'Below' -->
      +    <direction>Vertical</direction>
      +    <!-- 'Vertical' or 'Horizontal' -->
      +    <autoHide>no</autoHide>
      +    <hideDelay>300</hideDelay>
      +    <!-- in milliseconds (1000 = 1 second) -->
      +    <showDelay>300</showDelay>
      +    <!-- in milliseconds (1000 = 1 second) -->
      +    <moveButton>Middle</moveButton>
      +    <!-- 'Left', 'Middle', 'Right' -->
      +  </dock>
      +  <keyboard>
      +    <chainQuitKey>C-g</chainQuitKey>
      +    <!-- Keybindings for desktop switching -->
      +    <keybind key="C-A-Left">
      +      <action name="GoToDesktop">
      +        <to>left</to>
      +        <wrap>no</wrap>
      +      </action>
      +    </keybind>
      +    <keybind key="C-A-Right">
      +      <action name="GoToDesktop">
      +        <to>right</to>
      +        <wrap>no</wrap>
      +      </action>
      +    </keybind>
      +    <keybind key="C-A-Up">
      +      <action name="GoToDesktop">
      +        <to>up</to>
      +        <wrap>no</wrap>
      +      </action>
      +    </keybind>
      +    <keybind key="C-A-Down">
      +      <action name="GoToDesktop">
      +        <to>down</to>
      +        <wrap>no</wrap>
      +      </action>
      +    </keybind>
      +    <keybind key="S-A-Left">
      +      <action name="SendToDesktop">
      +        <to>left</to>
      +        <wrap>no</wrap>
      +      </action>
      +    </keybind>
      +    <keybind key="S-A-Right">
      +      <action name="SendToDesktop">
      +        <to>right</to>
      +        <wrap>no</wrap>
      +      </action>
      +    </keybind>
      +    <keybind key="S-A-Up">
      +      <action name="SendToDesktop">
      +        <to>up</to>
      +        <wrap>no</wrap>
      +      </action>
      +    </keybind>
      +    <keybind key="S-A-Down">
      +      <action name="SendToDesktop">
      +        <to>down</to>
      +        <wrap>no</wrap>
      +      </action>
      +    </keybind>
      +    <keybind key="W-F1">
      +      <action name="GoToDesktop">
      +        <to>1</to>
      +      </action>
      +    </keybind>
      +    <keybind key="W-F2">
      +      <action name="GoToDesktop">
      +        <to>2</to>
      +      </action>
      +    </keybind>
      +    <keybind key="W-F3">
      +      <action name="GoToDesktop">
      +        <to>3</to>
      +      </action>
      +    </keybind>
      +    <keybind key="W-F4">
      +      <action name="GoToDesktop">
      +        <to>4</to>
      +      </action>
      +    </keybind>
      +    <keybind key="W-d">
      +      <action name="ToggleShowDesktop"/>
      +    </keybind>
      +    <!-- Keybindings for windows -->
      +    <keybind key="A-F4">
      +      <action name="Close"/>
      +    </keybind>
      +    <keybind key="A-Escape">
      +      <action name="Lower"/>
      +      <action name="FocusToBottom"/>
      +      <action name="Unfocus"/>
      +    </keybind>
      +    <keybind key="A-space">
      +      <action name="ShowMenu">
      +        <menu>client-menu</menu>
      +      </action>
      +    </keybind>
      +    <!-- Take a screenshot of the current window with scrot when Alt+Print are pressed -->
      +    <keybind key="A-Print">
      +      <action name="Execute">
      +        <command>scrot -s</command>
      +      </action>
      +    </keybind>
      +    <!-- Keybindings for window switching -->
      +    <keybind key="A-Tab">
      +      <action name="NextWindow">
      +        <finalactions>
      +          <action name="Focus"/>
      +          <action name="Raise"/>
      +          <action name="Unshade"/>
      +        </finalactions>
      +      </action>
      +    </keybind>
      +    <keybind key="A-S-Tab">
      +      <action name="PreviousWindow">
      +        <finalactions>
      +          <action name="Focus"/>
      +          <action name="Raise"/>
      +          <action name="Unshade"/>
      +        </finalactions>
      +      </action>
      +    </keybind>
      +    <keybind key="C-A-Tab">
      +      <action name="NextWindow">
      +        <panels>yes</panels>
      +        <desktop>yes</desktop>
      +        <finalactions>
      +          <action name="Focus"/>
      +          <action name="Raise"/>
      +          <action name="Unshade"/>
      +        </finalactions>
      +      </action>
      +    </keybind>
      +    <!-- Keybindings for window switching with the arrow keys -->
      +    <keybind key="W-S-Right">
      +      <action name="DirectionalCycleWindows">
      +        <direction>right</direction>
      +      </action>
      +    </keybind>
      +    <keybind key="W-S-Left">
      +      <action name="DirectionalCycleWindows">
      +        <direction>left</direction>
      +      </action>
      +    </keybind>
      +    <keybind key="W-S-Up">
      +      <action name="DirectionalCycleWindows">
      +        <direction>up</direction>
      +      </action>
      +    </keybind>
      +    <keybind key="W-S-Down">
      +      <action name="DirectionalCycleWindows">
      +        <direction>down</direction>
      +      </action>
      +    </keybind>
      +  </keyboard>
      +  <mouse>
      +    <dragThreshold>1</dragThreshold>
      +    <!-- number of pixels the mouse must move before a drag begins -->
      +    <doubleClickTime>500</doubleClickTime>
      +    <!-- in milliseconds (1000 = 1 second) -->
      +    <screenEdgeWarpTime>400</screenEdgeWarpTime>
      +    <!-- Time before changing desktops when the pointer touches the edge of the
      +       screen while moving a window, in milliseconds (1000 = 1 second).
      +       Set this to 0 to disable warping -->
      +    <screenEdgeWarpMouse>false</screenEdgeWarpMouse>
      +    <!-- Set this to TRUE to move the mouse pointer across the desktop when
      +       switching due to hitting the edge of the screen -->
      +    <context name="Frame">
      +      <mousebind button="A-Left" action="Press">
      +        <action name="Focus"/>
      +        <action name="Raise"/>
      +      </mousebind>
      +      <mousebind button="A-Left" action="Click">
      +        <action name="Unshade"/>
      +      </mousebind>
      +      <mousebind button="A-Left" action="Drag">
      +        <action name="Move"/>
      +      </mousebind>
      +      <mousebind button="A-Right" action="Press">
      +        <action name="Focus"/>
      +        <action name="Raise"/>
      +        <action name="Unshade"/>
      +      </mousebind>
      +      <mousebind button="A-Right" action="Drag">
      +        <action name="Resize"/>
      +      </mousebind>
      +      <mousebind button="A-Middle" action="Press">
      +        <action name="Lower"/>
      +        <action name="FocusToBottom"/>
      +        <action name="Unfocus"/>
      +      </mousebind>
      +      <mousebind button="A-Up" action="Click">
      +        <action name="GoToDesktop">
      +          <to>previous</to>
      +        </action>
      +      </mousebind>
      +      <mousebind button="A-Down" action="Click">
      +        <action name="GoToDesktop">
      +          <to>next</to>
      +        </action>
      +      </mousebind>
      +      <mousebind button="C-A-Up" action="Click">
      +        <action name="GoToDesktop">
      +          <to>previous</to>
      +        </action>
      +      </mousebind>
      +      <mousebind button="C-A-Down" action="Click">
      +        <action name="GoToDesktop">
      +          <to>next</to>
      +        </action>
      +      </mousebind>
      +      <mousebind button="A-S-Up" action="Click">
      +        <action name="SendToDesktop">
      +          <to>previous</to>
      +        </action>
      +      </mousebind>
      +      <mousebind button="A-S-Down" action="Click">
      +        <action name="SendToDesktop">
      +          <to>next</to>
      +        </action>
      +      </mousebind>
      +    </context>
      +    <context name="Titlebar">
      +      <mousebind button="Left" action="Drag">
      +        <action name="Move"/>
      +      </mousebind>
      +      <mousebind button="Left" action="DoubleClick">
      +        <action name="ToggleMaximize"/>
      +      </mousebind>
      +      <mousebind button="Up" action="Click">
      +        <action name="if">
      +          <shaded>no</shaded>
      +          <then>
      +            <action name="Shade"/>
      +            <action name="FocusToBottom"/>
      +            <action name="Unfocus"/>
      +            <action name="Lower"/>
      +          </then>
      +        </action>
      +      </mousebind>
      +      <mousebind button="Down" action="Click">
      +        <action name="if">
      +          <shaded>yes</shaded>
      +          <then>
      +            <action name="Unshade"/>
      +            <action name="Raise"/>
      +          </then>
      +        </action>
      +      </mousebind>
      +    </context>
      +    <context name="Titlebar Top Right Bottom Left TLCorner TRCorner BRCorner BLCorner">
      +      <mousebind button="Left" action="Press">
      +        <action name="Focus"/>
      +        <action name="Raise"/>
      +        <action name="Unshade"/>
      +      </mousebind>
      +      <mousebind button="Middle" action="Press">
      +        <action name="Lower"/>
      +        <action name="FocusToBottom"/>
      +        <action name="Unfocus"/>
      +      </mousebind>
      +      <mousebind button="Right" action="Press">
      +        <action name="Focus"/>
      +        <action name="Raise"/>
      +        <action name="ShowMenu">
      +          <menu>client-menu</menu>
      +        </action>
      +      </mousebind>
      +    </context>
      +    <context name="Top">
      +      <mousebind button="Left" action="Drag">
      +        <action name="Resize">
      +          <edge>top</edge>
      +        </action>
      +      </mousebind>
      +    </context>
      +    <context name="Left">
      +      <mousebind button="Left" action="Drag">
      +        <action name="Resize">
      +          <edge>left</edge>
      +        </action>
      +      </mousebind>
      +    </context>
      +    <context name="Right">
      +      <mousebind button="Left" action="Drag">
      +        <action name="Resize">
      +          <edge>right</edge>
      +        </action>
      +      </mousebind>
      +    </context>
      +    <context name="Bottom">
      +      <mousebind button="Left" action="Drag">
      +        <action name="Resize">
      +          <edge>bottom</edge>
      +        </action>
      +      </mousebind>
      +      <mousebind button="Right" action="Press">
      +        <action name="Focus"/>
      +        <action name="Raise"/>
      +        <action name="ShowMenu">
      +          <menu>client-menu</menu>
      +        </action>
      +      </mousebind>
      +    </context>
      +    <context name="TRCorner BRCorner TLCorner BLCorner">
      +      <mousebind button="Left" action="Press">
      +        <action name="Focus"/>
      +        <action name="Raise"/>
      +        <action name="Unshade"/>
      +      </mousebind>
      +      <mousebind button="Left" action="Drag">
      +        <action name="Resize"/>
      +      </mousebind>
      +    </context>
      +    <context name="Client">
      +      <mousebind button="Left" action="Press">
      +        <action name="Focus"/>
      +        <action name="Raise"/>
      +      </mousebind>
      +      <mousebind button="Middle" action="Press">
      +        <action name="Focus"/>
      +        <action name="Raise"/>
      +      </mousebind>
      +      <mousebind button="Right" action="Press">
      +        <action name="Focus"/>
      +        <action name="Raise"/>
      +      </mousebind>
      +    </context>
      +    <context name="Icon">
      +      <mousebind button="Left" action="Press">
      +        <action name="Focus"/>
      +        <action name="Raise"/>
      +        <action name="Unshade"/>
      +        <action name="ShowMenu">
      +          <menu>client-menu</menu>
      +        </action>
      +      </mousebind>
      +      <mousebind button="Right" action="Press">
      +        <action name="Focus"/>
      +        <action name="Raise"/>
      +        <action name="ShowMenu">
      +          <menu>client-menu</menu>
      +        </action>
      +      </mousebind>
      +    </context>
      +    <context name="AllDesktops">
      +      <mousebind button="Left" action="Press">
      +        <action name="Focus"/>
      +        <action name="Raise"/>
      +        <action name="Unshade"/>
      +      </mousebind>
      +      <mousebind button="Left" action="Click">
      +        <action name="ToggleOmnipresent"/>
      +      </mousebind>
      +    </context>
      +    <context name="Shade">
      +      <mousebind button="Left" action="Press">
      +        <action name="Focus"/>
      +        <action name="Raise"/>
      +      </mousebind>
      +      <mousebind button="Left" action="Click">
      +        <action name="ToggleShade"/>
      +      </mousebind>
      +    </context>
      +    <context name="Iconify">
      +      <mousebind button="Left" action="Press">
      +        <action name="Focus"/>
      +        <action name="Raise"/>
      +      </mousebind>
      +      <mousebind button="Left" action="Click">
      +        <action name="Iconify"/>
      +      </mousebind>
      +    </context>
      +    <context name="Maximize">
      +      <mousebind button="Left" action="Press">
      +        <action name="Focus"/>
      +        <action name="Raise"/>
      +        <action name="Unshade"/>
      +      </mousebind>
      +      <mousebind button="Middle" action="Press">
      +        <action name="Focus"/>
      +        <action name="Raise"/>
      +        <action name="Unshade"/>
      +      </mousebind>
      +      <mousebind button="Right" action="Press">
      +        <action name="Focus"/>
      +        <action name="Raise"/>
      +        <action name="Unshade"/>
      +      </mousebind>
      +      <mousebind button="Left" action="Click">
      +        <action name="ToggleMaximize"/>
      +      </mousebind>
      +      <mousebind button="Middle" action="Click">
      +        <action name="ToggleMaximize">
      +          <direction>vertical</direction>
      +        </action>
      +      </mousebind>
      +      <mousebind button="Right" action="Click">
      +        <action name="ToggleMaximize">
      +          <direction>horizontal</direction>
      +        </action>
      +      </mousebind>
      +    </context>
      +    <context name="Close">
      +      <mousebind button="Left" action="Press">
      +        <action name="Focus"/>
      +        <action name="Raise"/>
      +        <action name="Unshade"/>
      +      </mousebind>
      +      <mousebind button="Left" action="Click">
      +        <action name="Close"/>
      +      </mousebind>
      +    </context>
      +    <context name="Desktop">
      +      <mousebind button="Up" action="Click">
      +        <action name="GoToDesktop">
      +          <to>previous</to>
      +        </action>
      +      </mousebind>
      +      <mousebind button="Down" action="Click">
      +        <action name="GoToDesktop">
      +          <to>next</to>
      +        </action>
      +      </mousebind>
      +      <mousebind button="A-Up" action="Click">
      +        <action name="GoToDesktop">
      +          <to>previous</to>
      +        </action>
      +      </mousebind>
      +      <mousebind button="A-Down" action="Click">
      +        <action name="GoToDesktop">
      +          <to>next</to>
      +        </action>
      +      </mousebind>
      +      <mousebind button="C-A-Up" action="Click">
      +        <action name="GoToDesktop">
      +          <to>previous</to>
      +        </action>
      +      </mousebind>
      +      <mousebind button="C-A-Down" action="Click">
      +        <action name="GoToDesktop">
      +          <to>next</to>
      +        </action>
      +      </mousebind>
      +      <mousebind button="Left" action="Press">
      +        <action name="Focus"/>
      +        <action name="Raise"/>
      +      </mousebind>
      +      <mousebind button="Right" action="Press">
      +        <action name="Focus"/>
      +        <action name="Raise"/>
      +      </mousebind>
      +    </context>
      +    <context name="Root">
      +      <!-- Menus -->
      +      <mousebind button="Middle" action="Press">
      +        <action name="ShowMenu">
      +          <menu>client-list-combined-menu</menu>
      +        </action>
      +      </mousebind>
      +      <mousebind button="Right" action="Press">
      +        <action name="ShowMenu">
      +          <menu>root-menu</menu>
      +        </action>
      +      </mousebind>
      +    </context>
      +    <context name="MoveResize">
      +      <mousebind button="Up" action="Click">
      +        <action name="GoToDesktop">
      +          <to>previous</to>
      +        </action>
      +      </mousebind>
      +      <mousebind button="Down" action="Click">
      +        <action name="GoToDesktop">
      +          <to>next</to>
      +        </action>
      +      </mousebind>
      +      <mousebind button="A-Up" action="Click">
      +        <action name="GoToDesktop">
      +          <to>previous</to>
      +        </action>
      +      </mousebind>
      +      <mousebind button="A-Down" action="Click">
      +        <action name="GoToDesktop">
      +          <to>next</to>
      +        </action>
      +      </mousebind>
      +    </context>
      +  </mouse>
      +  <menu>
      +    <!-- You can specify more than one menu file in here and they are all loaded,
      +       just don't make menu ids clash or, well, it'll be kind of pointless -->
      +    <!-- default menu file (or custom one in $HOME/.config/openbox/) -->
      +    <!-- system menu files on Debian systems -->
      +    <file>/var/lib/openbox/debian-menu.xml</file>
      +    <file>menu.xml</file>
      +    <hideDelay>200</hideDelay>
      +    <!-- if a press-release lasts longer than this setting (in milliseconds), the
      +       menu is hidden again -->
      +    <middle>no</middle>
      +    <!-- center submenus vertically about the parent entry -->
      +    <submenuShowDelay>100</submenuShowDelay>
      +    <!-- time to delay before showing a submenu after hovering over the parent
      +       entry.
      +       if this is a negative value, then the delay is infinite and the
      +       submenu will not be shown until it is clicked on -->
      +    <submenuHideDelay>400</submenuHideDelay>
      +    <!-- time to delay before hiding a submenu when selecting another
      +       entry in parent menu
      +       if this is a negative value, then the delay is infinite and the
      +       submenu will not be hidden until a different submenu is opened -->
      +    <showIcons>yes</showIcons>
      +    <!-- controls if icons appear in the client-list-(combined-)menu -->
      +    <manageDesktops>yes</manageDesktops>
      +    <!-- show the manage desktops section in the client-list-(combined-)menu -->
      +  </menu>
      +    <!--
      +  # this is an example with comments through out. use these to make your
      +  # own rules, but without the comments of course.
      +  # you may use one or more of the name/class/role/title/type rules to specify
      +  # windows to match
      +
      +  <application name="the window's _OB_APP_NAME property (see obxprop)"
      +              class="the window's _OB_APP_CLASS property (see obxprop)"
      +          groupname="the window's _OB_APP_GROUP_NAME property (see obxprop)"
      +         groupclass="the window's _OB_APP_GROUP_CLASS property (see obxprop)"
      +               role="the window's _OB_APP_ROLE property (see obxprop)"
      +              title="the window's _OB_APP_TITLE property (see obxprop)"
      +               type="the window's _OB_APP_TYPE property (see obxprob)..
      +                      (if unspecified, then it is 'dialog' for child windows)">
      +  # you may set only one of name/class/role/title/type, or you may use more
      +  # than one together to restrict your matches.
      +
      +  # the name, class, role, and title use simple wildcard matching such as those
      +  # used by a shell. you can use * to match any characters and ? to match
      +  # any single character.
      +
      +  # the type is one of: normal, dialog, splash, utility, menu, toolbar, dock,
      +  #    or desktop
      +
      +  # when multiple rules match a window, they will all be applied, in the
      +  # order that they appear in this list
      +
      +
      +    # each rule element can be left out or set to 'default' to specify to not 
      +    # change that attribute of the window
      +
      +    <decor>yes</decor>
      +    # enable or disable window decorations
      +
      +    <shade>no</shade>
      +    # make the window shaded when it appears, or not
      +
      +    <position force="no">
      +      # the position is only used if both an x and y coordinate are provided
      +      # (and not set to 'default')
      +      # when force is "yes", then the window will be placed here even if it
      +      # says you want it placed elsewhere.  this is to override buggy
      +      # applications who refuse to behave
      +      <x>center</x>
      +      # a number like 50, or 'center' to center on screen. use a negative number
      +      # to start from the right (or bottom for <y>), ie -50 is 50 pixels from
      +      # the right edge (or bottom). use 'default' to specify using value
      +      # provided by the application, or chosen by openbox, instead.
      +      <y>200</y>
      +      <monitor>1</monitor>
      +      # specifies the monitor in a xinerama setup.
      +      # 1 is the first head, or 'mouse' for wherever the mouse is
      +    </position>
      +
      +    <size>
      +      # the size to make the window.
      +      <width>20</width>
      +      # a number like 20, or 'default' to use the size given by the application.
      +      # you can use fractions such as 1/2 or percentages such as 75% in which
      +      # case the value is relative to the size of the monitor that the window
      +      # appears on.
      +      <height>30%</height>
      +    </size>
      +
      +    <focus>yes</focus>
      +    # if the window should try be given focus when it appears. if this is set
      +    # to yes it doesn't guarantee the window will be given focus. some
      +    # restrictions may apply, but Openbox will try to
      +
      +    <desktop>1</desktop>
      +    # 1 is the first desktop, 'all' for all desktops
      +
      +    <layer>normal</layer>
      +    # 'above', 'normal', or 'below'
      +
      +    <iconic>no</iconic>
      +    # make the window iconified when it appears, or not
      +
      +    <skip_pager>no</skip_pager>
      +    # asks to not be shown in pagers
      +
      +    <skip_taskbar>no</skip_taskbar>
      +    # asks to not be shown in taskbars. window cycling actions will also
      +    # skip past such windows
      +
      +    <fullscreen>yes</fullscreen>
      +    # make the window in fullscreen mode when it appears
      +
      +    <maximized>true</maximized>
      +    # 'Horizontal', 'Vertical' or boolean (yes/no)
      +  </application>
      +
      +  # end of the example
      +-->
      +  <applications>
      +    <application title="softhddevice">
      +      <decor>no</decor>
      +      <maximized>yes</maximized>
      +      <!--<skip_pager>yes</skip_pager>-->
      +      <skip_taskbar>no</skip_taskbar>
      +    </application>
      +    <application class="VDR">
      +      <decor>no</decor>
      +      <maximized>yes</maximized>
      +      <!--<skip_pager>yes</skip_pager>-->
      +      <skip_taskbar>no</skip_taskbar>
      +    </application>
      +    <application title="browser">
      +      <decor>no</decor>
      +      <maximized>yes</maximized>
      +      <!--<skip_pager>yes</skip_pager>-->
      +      <skip_taskbar>no</skip_taskbar>
      +    </application>
      +    <application title="osd2Web">
      +      <decor>no</decor>
      +      <maximized>yes</maximized>
      +      <!--<skip_pager>yes</skip_pager>-->
      +      <skip_taskbar>no</skip_taskbar>
      +    </application>
      +  </applications>
      +</openbox_config>
      +
      +
      +
      +
      +
    4. +
    +
  10. +
+
+
+ +
+

7.11 samba-install

+
+
+
+

7.11.1 tasks

+
+
+
---
+# file: roles/samba-install/tasks/main.yml
+
+- name: install samba server
+  apt:
+    name: '{{ item }}'
+    state: present
+    install_recommends: no
+  with_items:
+    - samba
+    - samba-common
+    - samba-common-bin
+    - tdb-tools
+
+
+
+
+
+
+
+

7.12 samba-config

+
+
+
+

7.12.1 tasks

+
+
+
---
+# file: roles/samba-config/tasks/main.yml
+
+# TODO:
+# - name: divert original smbd.conf
+
+- name: touch smb.conf.custom
+  file:
+    state: touch
+    dest: '/etc/samba/smb.conf.custom'
+  notify: [ 'Restart Samba' ]
+    
+- name: expand template for smb.conf
+  template:
+    src: 'templates/smb.conf.j2'
+    dest: '/etc/samba/smb.conf'
+    #validate: 'testparm -s %s'
+  notify: [ 'Restart Samba' ]
+
+
+
+
+
+

7.12.2 templates

+
+
+
    +
  1. smb.conf
    +
      +
    1. global settings
      +
      +
      +
      {{ ansible_managed | comment }}
      +
      +#======================= Global Settings =======================
      +
      +[global]
      +
      +## Browsing/Identification ###
      +
      +# Change this to the workgroup/NT-domain name your Samba server will part of
      +   workgroup = {{ samba.workgroup }}
      +
      +# server string is the equivalent of the NT Description field
      +   server string = %h server (Samba, Ubuntu)
      +
      +# This will prevent nmbd to search for NetBIOS names through DNS.
      +   dns proxy = no
      +
      +#### Debugging/Accounting ####
      +
      +# This tells Samba to use a separate log file for each machine
      +# that connects
      +   log file = /var/log/samba/log.%m
      +
      +# Cap the size of the individual log files (in KiB).
      +   max log size = 1000
      +
      +# We want Samba to log a minimum amount of information to syslog. Everything
      +# should go to /var/log/samba/log.{smbd,nmbd} instead. If you want to log
      +# through syslog you should set the following parameter to something higher.
      +   syslog = 0
      +
      +# Do something sensible when Samba crashes: mail the admin a backtrace
      +   panic action = /usr/share/samba/panic-action %d
      +
      +
      +####### Authentication #######
      +
      +# "security = user" is always a good idea. This will require a Unix account
      +# in this server for every user accessing the server. See
      +# /usr/share/doc/samba-doc/htmldocs/Samba3-HOWTO/ServerType.html
      +# in the samba-doc package for details.
      +#   security = user
      +
      +# You may wish to use password encryption.  See the section on
      +# 'encrypt passwords' in the smb.conf(5) manpage before enabling.
      +   encrypt passwords = true
      +
      +# If you are using encrypted passwords, Samba will need to know what
      +# password database type you are using.  
      +   passdb backend = tdbsam
      +
      +   obey pam restrictions = yes
      +
      +# This boolean parameter controls whether Samba attempts to sync the Unix
      +# password with the SMB password when the encrypted SMB password in the
      +# passdb is changed.
      +   unix password sync = yes
      +
      +# For Unix password sync to work on a Debian GNU/Linux system, the following
      +# parameters must be set (thanks to Ian Kahan <<kahan@informatik.tu-muenchen.de> for
      +# sending the correct chat script for the passwd program in Debian Sarge).
      +   passwd program = /usr/bin/passwd %u
      +   passwd chat = *Enter\snew\s*\spassword:* %n\n *Retype\snew\s*\spassword:* %n\n *password\supdated\ssuccessfully* .
      +
      +# This boolean controls whether PAM will be used for password changes
      +# when requested by an SMB client instead of the program listed in
      +# 'passwd program'. The default is 'no'.
      +   pam password change = yes
      +
      +# This option controls how unsuccessful authentication attempts are mapped 
      +# to anonymous connections
      +   map to guest = bad user
      +
      +{% if samba.windows_compatible %}
      +# disable unix extensions and enable following symlinks
      +   unix extensions = no
      +   follow symlinks= yes
      +   wide links= yes
      +{% endif %}
      +
      +
      +
      +
    2. +
    3. media directories
      +
      +
      +
      {% for name, path in media_dirs.iteritems() %}
      +[{{ name }}]
      +   path = {{ path }}
      +   comment = {{ name }} on %h
      +   guest ok = yes
      +   writeable = yes
      +   browseable = yes
      +   create mode = 0664
      +   directory mode = 0775
      +   force user = {{ vdr.user }}
      +   force group = {{ vdr.group }}
      +   follow symlinks = yes
      +   wide links = yes
      +
      +{% endfor %}
      +
      +
      +
      +
    4. +
    5. include custom samba exports
      +
      +
      +
      include = /etc/samba/smb.conf.custom
      +
      +
      +
      +
    6. +
    +
  2. +
+
+
+
+

7.13 STARTED autoinstall-drivers

+
+

+It would be nice to be able to detect if it is suitable to install those drivers: +

+
+
+

7.13.1 TODO sundtek for Sundtek devices (local or network connection)

+
+

+Vendor-IDs: +

+
    +
  • eb1a:5[1b2] (alte Generation)
  • +
  • 2659:* (neuere Sticks)
  • +
+
+
+
+

7.13.2 TODO dddvb-dkms if only newer DD cards are detected

+
+
+

7.13.3 TODO media-build-experimental (up to kernel 4.8) for „old“ cards like TT S2-6400 FF

+
+ +
+ +
+

7.14 autoinstall-ubuntu-drivers

+
+

+The tool ubuntu-drivers is used to install the matching driver version for nvidia graphics cards, virtualbox guest additions and Intel and AMD microcode updates. +

+
+
+

7.14.1 tasks

+
+
+
---
+# file roles/autoinstall-ubuntu-drivers/tasks/main.yml
+
+- name: autoinstall ubuntu-drivers-common
+  block:
+    - name: apt | install ubuntu-drivers-common
+      apt:
+        name: ubuntu-drivers-common
+        state: present
+
+    - name: use ubuntu-drivers to install additional drivers automatically
+      command: ubuntu-drivers --package-list /etc/yavdr/autoinstalled autoinstall
+  when: (ansible_virtualization_type != "virtualbox" and ansible_virtualization_role != "guest") or
+        ansible_distribution_version != "16.04"
+        # ubuntu-drivers-common tries to autoinstall
+        # conflicting packages for virtualbox in Ubuntu 16.04 :(
+
+
+
+
+
+
+

7.15 autoinstall-virtualbox-guest

+
+

+This role installs the guest additions for virtualbox guests on Ubuntu 16.04 +

+ +
+
---
+# file roles/autoinstall-virtualbox-guest/tasks/main.yml
+
+- name: install virtualbox guest additions
+  block:
+    - name: install packages
+      apt:
+        state: present
+        name: '{{ item }}'
+      with_items:
+        - virtualbox-guest-dkms
+        - virtualbox-guest-x11
+        - dkms
+
+    # TODO: set xineliboutput as frontend
+  when:
+    - ansible_virtualization_type == "virtualbox"
+    - ansible_virtualization_role == "guest"
+    - ansible_distribution == "Ubuntu"
+    - ansible_distribution_version == "16.04"
+
+
+
+
+
+

7.16 autoinstall-atric-usb

+
+
+
+

7.16.1 dependencies

+
+
+
---
+dependencies:
+    - { role: collect-facts }
+    - { role: yavdr-remote }
+
+
+
+
+
+
+

7.16.2 tasks

+
+
+
---
+# file roles/autoinstall-atric-usb/tasks/main.yml
+
+- name: install and configure Atric IR-WakeupUSB
+  block:
+    - name: apt | install lirc-drv-irman
+      apt:
+        name: lirc-drv-irman
+        state: present
+      tags:
+        - packages
+
+    - name: write lirc configuration
+      template:
+        src: templates/lirc_options.conf.j2
+        dest: /etc/lirc/lirc_options.conf
+      tags:
+        - config
+        - systemd
+
+    - name: enable lircd, eventlircd, lircd2uinput
+      systemd:
+        name: '{{ item }}'
+        enabled: yes
+        state: started
+        masked: no
+        daemon_reload: yes
+      with_items:
+        - eventlircd.socket
+        - eventlircd.service
+        - lircd2uinput.service
+        - lircd.service
+      tags:
+        - systemd
+
+  when: '"04d8:f844" in usb'
+
+
+
+
+
+

7.16.3 templates

+
+
+
{{ ansible_managed | comment }}
+
+[lircd]
+nodaemon        = False
+driver          = irman
+device          = /dev/irman
+output          = /var/run/lirc/lircd0
+pidfile         = /var/run/lirc/lircd0.pid
+plugindir       = /usr/lib/x86_64-linux-gnu/lirc/plugins
+permission      = 666
+allow-simulate  = No
+repeat-max      = 600
+#loglevel       = 6
+#release        = true
+#release_suffix = _EVUP
+#logfile        = ...
+#driver-options = ...
+
+[lircmd]
+uinput          = False
+nodaemon        = False
+
+
+
+
+
+
+

7.17 autoinstall-yausbir

+
+
+
+

7.17.1 dependencies

+
+
+
---
+dependencies:
+    - { role: yavdr-remote }
+
+
+
+
+
+
+

7.17.2 tasks

+
+
+
---
+# file roles/autoinstall-atric-usb/tasks/main.yml
+
+- name: install and configure Atric IR-WakeupUSB
+  block:
+    - name: apt | install lirc-drv-yausbir
+      apt:
+        name: lirc-drv-yausbir
+        state: present
+      tags:
+        - packages
+
+    - name: write lirc configuration
+      template:
+        src: templates/lirc_options.conf.j2
+        dest: /etc/lirc/lirc_options.conf
+      tags:
+        - config
+        - systemd
+
+    - name: enable lircd, eventlircd, lircd2uinput
+      systemd:
+        name: '{{ item }}'
+        enabled: yes
+        state: started
+        masked: no
+        daemon_reload: yes
+      with_items:
+        - eventlircd.socket
+        - eventlircd.service
+        - lircd2uinput.service
+        - lircd.service
+      tags:
+        - systemd
+
+  when: '"10c4:876c" in usb'
+
+
+
+
+
+

7.17.3 templates

+
+
+
{{ ansible_managed | comment }}
+
+[lircd]
+nodaemon        = False
+driver          = ya_usbir
+output          = /var/run/lirc/lircd0
+pidfile         = /var/run/lirc/lircd0.pid
+plugindir       = /usr/lib/x86_64-linux-gnu/lirc/plugins
+permission      = 666
+allow-simulate  = No
+repeat-max      = 600
+#loglevel       = 6
+#release        = true
+#release_suffix = _EVUP
+#logfile        = ...
+#driver-options = ...
+
+[lircmd]
+uinput          = False
+nodaemon        = False
+
+
+
+
+
+
+

7.18 autoinstall-satip

+
+

+If a Sat>IP Server responds to a discovery request, the package vdr-plugin-satip is installed. +

+
+
+

7.18.1 tasks

+
+
+
---
+# file roles/autoinstall-satip/tasks/main.yml
+
+- name: "detect SAT>IP Server(s) on the network"
+  action: satip_facts
+
+- debug:
+    var: satip_devices
+    verbosity: 1
+
+- name: apt | install vdr-plugin-satip if a Sat>IP server has been detected
+  apt:
+    name: vdr-plugin-satip
+    state: present
+  when: satip_devices
+  notify: [ 'Restart VDR' ]
+
+
+
+
+
+ +
+

7.19 autoinstall-targavfd

+
+
+
+

7.19.1 tasks

+
+
+
---
+# file roles/autoinstall-targavfd/tasks/main.yml
+
+- name: apt | install vdr-plugin-targavfd if connected
+  apt:
+    name: vdr-plugin-targavfd
+  when: '"19c2:6a11" in usb'
+  notify: [ 'Restart VDR' ]
+
+
+
+
+
+
+

7.20 autoinstall-imonlcd

+
+
+
+

7.20.1 tasks

+
+
+
---
+# file roles/autoinstall-imonlcd/tasks/main.yml
+
+- name: apt | install vdr-plugin-imonlcd if connected
+  apt:
+    name: vdr-plugin-imonlcd
+  when: '"15c2:0038" in usb or "15c2:ffdc" in usb'
+  notify: [ 'Restart VDR' ]
+
+
+
+
+
+
+

7.21 autoinstall-libcecdaemon

+
+
+
+

7.21.1 tasks

+
+
+
---
+# file roles/autoinstall-libcec-daemon/tasks/main.yml
+
+- name: apt | install libcec-daemon if connected
+  apt:
+    name: libcec-daemon
+  when: 
+    - "2548:1002" in usb
+
+
+
+
+
+
+

7.22 autoinstall-pvr350

+
+
+
+

7.22.1 tasks

+
+
+
---
+# file roles/autoinstall-pvr350/tasks/main.yml
+
+- name: apt | install vdr-plugin-pvr350 if connected
+  apt:
+    name: vdr-plugin-pvr350
+  when: '"0070:4000" in pci'
+  notify: [ 'Restart VDR' ]
+
+
+
+
+
+
+

7.23 autoinstall-hauppauge-pvr

+
+
+
---
+# file roles/autoinstall-hauppauge-pvr/tasks/main.yml
+
+- name: apt | install vdr-plugin-pvrinput if a haupauge pvr card is found
+  apt:
+    name: vdr-plugin-pvrinput
+  when: '"0070:4000" in pci or "4444:0016" in pci'
+  notify: [ 'Restart VDR' ]
+
+
+
+
+
+

7.24 autoinstall-firmware

+
+
+
+

7.24.1 dependencies

+
+
+
---
+dependencies:
+  - { role: collect-facts }
+
+
+
+
+
+
+

7.24.2 tasks

+
+
+
---
+
+# This role provides easyily downloadable firmware files
+
+- name: Firmware for Hauppauge WinTV HD Solo/Duo, PCTV 292e
+  get_url:
+    url: https://github.com/OpenELEC/dvb-firmware/raw/master/firmware/dvb-demod-si2168-b40-01.fw
+    checksum: sha256:8507536630d75a316d0719d6b95c04b90c36baa5b457ad457c9bacadafcef134
+    dest: /lib/firmware/dvb-demod-si2168-b40-01.fw
+  when: '"2040:0264" in usb or "2013:025f" in usb'
+
+- name: Firmware for Hauppauge WinTV-HVR-930C
+  get_url:
+    url: https://github.com/OpenELEC/dvb-firmware/raw/master/firmware/dvb-fe-xc5000-1.6.114.fw
+    checksum: sha256:7104bda8df301fe1bd4c09de1708aeb6d0d8e1f9d55505449fecfad82639235f
+    dest: /lib/firmware/dvb-fe-xc5000-1.6.114.fw
+  when: '"2040:1605" in usb'
+
+
+
+
+
+
+

7.25 autoinstall-dvbsky-firmware

+
+
+
+

7.25.1 dependencies

+
+
+
---
+dependencies:
+  - { role: collect-facts }
+
+
+
+
+
+
+

7.25.2 defaults

+
+
+
---
+# file roles/autoinstall-dvbsky-firmware
+dvbsky_firmware_files: []
+
+
+
+
+
+

7.25.3 tasks

+
+
+
---
+# file roles/autoinstall-dvbsky-firmware/tasks/main.yml
+
+- name: determine needed firmware files by device ids
+  block:
+    - name: add firmware files for DVBSky if a card has been detected
+      set_fact:
+        dvbsky_firmware_files: ['dvb-demod-m88ds3103.fw', 'dvb-demod-m88rs6000.fw', 'dvb-tuner-si2158-a20-01.fw', 'dvb-demod-si2168-a20-01.fw', 'dvb-demod-si2168-a30-01.fw', 'dvb-demod-si2168-b40-01.fw', 'dvb-fe-ds300x.fw', 'dvb-fe-ds3103.fw', 'dvb-fe-rs6000.fw']
+      when:
+        - '"1ade:3038" in pci'
+  when:
+    - not dvbsky_firmware_files
+
+- name: Download firmware for DVBSky cards and copy required files to /lib/firmware
+  block:
+    # download and extract firmware
+    - unarchive:
+        src: http://www.dvbsky.net/download/linux/dvbsky-firmware.tar.gz
+        dest: /tmp/
+        remote_src: yes
+
+    # copy firmware file
+    - copy:
+        src: "/tmp/dvbsky-firmware/{{ item }}"
+        dest: /lib/firmware/
+        owner: root
+        group: root
+        mode: 0644
+      with_items: '{{ dvbsky_firmware_files }}'
+      notify: ['Trigger Udev']
+
+    # Remove temporary files
+    - file:
+        path: /tmp/dvbsky-firmware
+        state: absent
+  when:
+    - dvbsky_firmware_files is defined
+    - dvbsky_firmware_files
+  tags:
+    - install
+    - autodetect
+    - dvbsky
+
+
+
+
+
+
+

7.26 TODO autoinstall-dvbhddevice

+
+

+Problem: woher kommt der Treiber (AFAIK noch nicht im Kernel)? Die Firmware sollte in yavdr-firmware stecken +

+
+
+

7.26.1 dependencies

+
+
+
---
+dependencies:
+    - { role: collect-facts }
+
+
+
+
+
+
+

7.26.2 tasks

+
+
+
---
+# file roles/autoinstall-dvbhddevice/tasks/main.yml
+
+- name: apt | install vdr-plugin-dvbhddevice if connected
+  apt:
+    name: vdr-plugin-dvbhddevice
+  when: '"13c2:300a" in pci or "13c2:300b" in pci'
+  notify: [ 'Restart VDR' ]
+
+
+
+
+
+ +
+

7.27 autoinstall-dvbsddevice

+
+
+
+

7.27.1 dependencies

+
+
+
---
+dependencies:
+  - { role: collect-facts }
+
+
+
+
+
+
+

7.27.2 tasks

+
+
+
---
+# file roles/autoinstall-dvbsddevice/tasks/main.yml
+
+# TODO: install firmware
+
+- name: apt | install vdr-plugin-dvbsddevice if module is loaded
+  apt:
+    name: vdr-plugin-dvbsddevice
+  when: '"dvb_ttpci" in modules'
+  notify: [ 'Restart VDR' ]
+
+
+
+
+
+
+

7.28 autoinstall-hardware-irmp

+
+
+
+

7.28.1 dependencies

+
+
+
---
+dependencies:
+  - { role: collect-facts }
+
+
+
+
+
+
+

7.28.2 tasks

+
+
+
---
+# file roles/autoinstall-hardware-irmp/tasks/main.yml
+
+- name: apt | install yavdr-hardware-irmp if connected
+  apt:
+    name: yavdr-hardware-irmp
+    state: present
+  when: '"1209:4444" in usb'
+
+
+
+ +
    +
  1. TODO add other device ids if necessary
  2. +
+
+
+ +
+

7.29 kodi

+
+
+
+

7.29.1 tasks

+
+
+
    +
  1. Install KODI
    +
      +
    • main.yml
      +
      +
      +
      - import_tasks: install-kodi.yml tags=install,update,kodi:install
      +- import_tasks: configure-kodi.yml tags=install,update,kodi:configure
      +
      +
      +
      +
    • +
    • install-kodi.yml
      +
      +
      +
      ---
      +
      +- name: apt | install kodi packages
      +  apt:
      +    name: '{{ item }}'
      +    state: present
      +    install_recommends: no
      +  with_items:
      +    - kodi
      +    - kodi-pvr-vdr-vnsi
      +    - kodi-eventclients-kodi-send # for ubuntu packages, team-xbmc uses "kodi-eventclients-xbmc-send for some reason
      +
      +
      +
      +
    • +
    • configure-kodi.yml
      +
      +
      +
      - name: create kodi.service for the user session
      +  template:
      +      src: 'templates/kodi.service.j2'
      +      dest: '{{ vdr.home }}/.config/systemd/user/kodi.service'
      +      mode: 0644
      +      owner: '{{ vdr.user }}'
      +      group: '{{ vdr.group }}'
      +
      +- name: create kodi user directory
      +  file:
      +      dest: '{{ vdr.home }}/{{ item }}'
      +      state: directory
      +      owner: '{{ vdr.user }}'
      +      group: '{{ vdr.group }}'
      +      mode: "0775"
      +  with_items:
      +      - .kodi
      +      - .kodi/userdata
      +      - .kodi/userdata/keymaps
      +
      +- name: copy Lircmap.xml if it does not exist yet
      +  copy:
      +      dest: '{{ vdr.home }}/.kodi/userdata/Lircmap.xml'
      +      src: 'files/userdata/Lircmap.xml'
      +      owner: '{{ vdr.user }}'
      +      group: '{{ vdr.group }}'    
      +      mode: "0664"
      +      force: no
      +
      +- name: copy remote.xml if it does not exist yet
      +  copy:
      +      dest: '{{ vdr.home }}/.kodi/userdata/keymaps/remote.xml'
      +      src: 'files/userdata/keymaps/remote.xml'
      +      owner: '{{ vdr.user }}'
      +      group: '{{ vdr.group }}'    
      +      mode: "0664"
      +      force: no
      +# TODO: Add configuration files
      +
      +
      +
      +
    • +
+ + +
+
+

7.29.2 templates

+
+
+
    +
  1. kodi.service
    +
    +

    +This systemd unit for the user session starts (and stops) kodi. +

    +
    +
    [Unit]
    +Description=Start kodi in user session
    +
    +[Service]
    +Type=simple
    +PassEnvironment=DISPLAY XDG_RUNTIME_DIR DBUS_SESSION_BUS_ADDRESS
    +ExecStartPre=-/usr/bin/set-kodi-display
    +ExecStart=/usr/bin/kodi -l /run/lirc/lircd
    +ExecStop=/bin/bash -c "/usr/bin/kodi-send --action=QUIT; while ps -p $MAINPID -o comm=; do sleep .25; done"
    +TimeoutStopSec=10
    +SuccessExitStatus=0 127
    +Restart=on-failure
    +
    +
    +
    +
  2. +
+
+ +
+

7.29.3 files

+
+

+Those configuration files provide a preconfiguration for kodi which overrides the system wide configuration +

+
+
    +
  1. Lircmap.xml
    +
    +

    +This file allows to map keys sent by remotes via eventlircd (which uses the name devinput) to kodi key names. +

    +
    +
    <lircmap>
    +    <remote device="linux-input-layer">
    +    <altname>cx23885_remote</altname>
    +    <altname>devinput</altname>
    +        <up>KEY_UP</up>
    +        <down>KEY_DOWN</down>
    +                <menu>KEY_MENU</menu>
    +        <select>KEY_OK</select>
    +        <back>KEY_ESC</back>
    +        <left>KEY_LEFT</left>
    +        <right>KEY_RIGHT</right>
    +        <red>KEY_RED</red>
    +        <green>KEY_GREEN</green>
    +        <yellow>KEY_YELLOW</yellow>
    +        <blue>KEY_BLUE</blue>
    +        <zero>KEY_0</zero>
    +        <one>KEY_1</one>
    +        <two>KEY_2</two>
    +        <three>KEY_3</three>
    +        <four>KEY_4</four>
    +        <five>KEY_5</five>
    +        <six>KEY_6</six>
    +        <seven>KEY_7</seven>
    +        <eight>KEY_8</eight>
    +        <nine>KEY_9</nine>
    +        <info>KEY_INFO</info>
    +        <play>KEY_PLAY</play>
    +        <play>KEY_PLAYPAUSE</play>
    +        <pause>KEY_PAUSE</pause>
    +        <stop>KEY_STOP</stop>
    +        <record>KEY_RECORD</record>
    +        <forward>KEY_FASTFORWARD</forward>
    +        <reverse>KEY_REWIND</reverse>
    +        <skipplus>KEY_NEXT</skipplus>
    +        <skipminus>KEY_BACK</skipminus>
    +        <power>KEY_POWER2</power>
    +        <channelplus>KEY_CHANNELUP</channelplus>
    +        <channelminus>KEY_CHANNELDOWN</channelminus>
    +        <title>KEY_PROG3</title>
    +        <volumeplus>KEY_VOLUMEUP</volumeplus>
    +        <volumeminus>KEY_VOLUMEDOWN</volumeminus>
    +                <teletext>KEY_TEXT</teletext>
    +        <mute>KEY_MUTE</mute>
    +        <start>KEY_SELECT</start>
    +        <subtitle>KEY_SUBTITLE</subtitle>
    +                <audio>KEY_MODE</audio>
    +        <mute>KEY_MUTE</mute>
    +        <myvideo>KEY_VIDEO</myvideo>
    +        <mymusic>KEY_AUDIO</mymusic>
    +        <mypictures>KEY_IMAGES</mypictures>
    +        <recordedtv>KEY_PVR</recordedtv>
    +                <guide>KEY_EPG</guide>
    +                <display>KEY_SCREEN</display>
    +                <enter>KEY_PROG4</enter>
    +                <playlist>KEY_ZOOM</playlist>
    +                <livetv>KEY_CHANNEL</livetv>
    +                <mytv>KEY_TV</mytv>
    +                <liveradio>KEY_FN</liveradio>
    +    </remote>
    +</lircmap>
    +
    +
    +
    +
  2. +
  3. keymaps
    +
    +

    +This file maps the keys defined in Lircmap.xml to actions within kodi. +

    +
    +
      +
    1. remote.xml
      +
      +
      +
      <!-- This file contains the mapping of keys (gamepad, remote, and keyboard) to actions within XBMC -->
      +<!-- The <global> section is a fall through - they will only be used if the button is not          -->
      +<!-- used in the current window's section.  Note that there is only handling                       -->
      +<!-- for a single action per button at this stage.                                                 -->
      +<!-- For joystick/gamepad configuration under linux/win32, see below as it differs from xbox       -->
      +<!-- gamepads.                                                                                     -->
      +
      +<!-- The format is:                      -->
      +<!--    <device>                         -->
      +<!--      <button>action</button>        -->
      +<!--    </device>                        -->
      +
      +<!-- To map keys from other remotes using the RCA protocol, you may add <universalremote> blocks -->
      +<!-- In this case, the tags used are <obc#> where # is the original button code (OBC) of the key -->
      +<!-- You set it up by adding a <universalremote> block to the window or <global> section:       -->
      +<!--    <universalremote>             -->
      +<!--       <obc45>Stop</obc45>         -->
      +<!--    </universalremote>            -->
      +<!-- To find out the OBC's of your remote, try enabling the <displayremotecodes> tag in AdvancedSettings.xml -->
      +
      +<!-- Note that the action can be a built-in function.                 -->
      +<!--  eg <B>XBMC.ActivateWindow(MyMusic)</B>                         -->
      +<!-- would automatically go to My Music on the press of the B button. -->
      +
      +<!-- Joysticks / Gamepads:                                                                    -->
      +<!--   See the sample PS3 controller configuration below for the format.                      -->
      +<!--                                                                                          -->
      +<!--  Joystick Name:                                                                          -->
      +<!--   Do 'cat /proc/bus/input/devices' or see your xbmc log file  to find the names of       -->
      +<!--   detected joysticks. The name used in the configuration should match the detected name. -->
      +<!--                                                                                          -->
      +<!--  Button Ids:                                                                             -->
      +<!--   'id' is the button ID used by SDL. Joystick button ids of connected joysticks appear   -->
      +<!--   in xbmc.log when they are pressed. Use your log to map custom buttons to actions.      -->
      +<!--                                                                                          -->
      +<!--  Axis Ids / Analog Controls                                                              -->
      +<!--   Coming soon.                                                                           -->
      +<keymap>
      +  <global>
      +    <universalremote>
      +       <obc150>XBMC.ejecttray()</obc150>
      +       <obc151>Playlist</obc151>
      +    </universalremote>
      +    <remote>
      +      <play>PlayPause</play>
      +      <pause>Pause</pause>
      +      <stop>Stop</stop>
      +      <forward>FastForward</forward>
      +      <reverse>Rewind</reverse>
      +      <left>Left</left>
      +      <right>Right</right>
      +      <up>Up</up>
      +      <down>Down</down>
      +      <select>Select</select>
      +      <pageplus>PageUp</pageplus>
      +      <pageminus>PageDown</pageminus>
      +      <back>ParentDir</back>
      +      <menu>PreviousMenu</menu>
      +      <title>ContextMenu</title>
      +      <info>Info</info>
      +      <skipplus>SkipNext</skipplus>
      +      <skipminus>SkipPrevious</skipminus>
      +      <display>FullScreen</display>
      +      <start>PreviousMenu</start>
      +      <record>Screenshot</record>
      +      <volumeplus>VolumeUp</volumeplus>
      +      <volumeminus>VolumeDown</volumeminus>
      +      <mute>Mute</mute>
      +      <power>XBMC.Quit()</power>
      +      <myvideo>XBMC.ActivateWindow(MyVideos)</myvideo>
      +      <mymusic>XBMC.ActivateWindow(MyMusic)</mymusic>
      +      <mypictures>XBMC.ActivateWindow(MyPictures)</mypictures>
      +      <!--- <mytv>XBMC.ActivateWindow(Home)</mytv> -->
      +      <recordedtv>XBMC.ActivateWindowAndFocus(MyPVR, 34,0, 13,0)</recordedtv>
      +      <!-- PVR: EPG -->
      +      <guide>XBMC.ActivateWindowAndFocus(MyPVR, 31,0, 10,0)</guide>
      +      <!-- PVR: Channellist -->
      +      <livetv>XBMC.ActivateWindowAndFocus(MyPVR, 32,0, 11,0)</livetv>
      +      <!-- PVR: Radio -->
      +      <liveradio>XBMC.ActivateWindowAndFocus(MyPVR, 33,0, 12,0)</liveradio>
      +      <red>XBMC.ActivateWindow(Home)</red>
      +      <yellow>XBMC.ActivateWindow(MyVideos)</yellow>
      +      <green>XBMC.ActivateWindow(MyMusic)</green>
      +      <!-- <blue>XBMC.ActivateWindow(MyPictures)</blue> -->
      +      <zero>Number0</zero>
      +      <one>Number1</one>
      +      <two>JumpSMS2</two>
      +      <three>JumpSMS3</three>
      +      <four>JumpSMS4</four>
      +      <five>JumpSMS5</five>
      +      <six>JumpSMS6</six>
      +      <seven>JumpSMS7</seven>
      +      <eight>JumpSMS8</eight>
      +      <nine>JumpSMS9</nine>
      +      <audio>AudioNextLanguage</audio>
      +      <subtitle>ShowSubtitles</subtitle>
      +      <enter>FullScreen</enter>
      +      <blue>ContextMenu</blue>
      +      <playlist>XBMC.ActivateWindow(MyMusicPlaylist)</playlist>
      +    </remote>
      +  </global>
      +  <Home>
      +    <remote>
      +      <menu>XBMC.Skin.ToggleSetting(HomeViewToggle)</menu>
      +      <info>XBMC.ActivateWindow(SystemInfo)</info>
      +      <clear>XBMC.ActivateWindow(Weather)</clear>
      +      <blue>XBMC.ActivateWindow(Settings)</blue>
      +      <red>FullScreen</red>
      +      <back>FullScreen</back>
      +    </remote>
      +  </Home>
      +  <MyFiles>
      +    <remote>
      +      <clear>Delete</clear>
      +    </remote>
      +  </MyFiles>
      +  <MyMusicPlaylist>
      +    <remote>
      +      <back>Playlist</back>      <!-- Close playlist -->
      +      <clear>Delete</clear>
      +    </remote>
      +  </MyMusicPlaylist>
      +  <MyMusicPlaylistEditor>
      +    <remote>
      +      <zero>Queue</zero>
      +    </remote>
      +  </MyMusicPlaylistEditor>
      +  <MyMusicFiles>
      +    <remote>
      +      <zero>Queue</zero>
      +      <star>Queue</star>
      +      <start>ContextMenu</start>
      +    </remote>
      +  </MyMusicFiles>
      +  <MyMusicLibrary>
      +    <remote>
      +      <zero>Queue</zero>
      +      <star>Queue</star>
      +    </remote>
      +  </MyMusicLibrary>
      +  <FullscreenVideo>
      +    <remote>
      +      <back>FullScreen</back>
      +      <zero>Number0</zero>
      +      <one>Number1</one>
      +      <two>Number2</two>
      +      <three>Number3</three>
      +      <four>Number4</four>
      +      <five>Number5</five>
      +      <six>Number6</six>
      +      <seven>Number7</seven>
      +      <eight>Number8</eight>
      +      <nine>Number9</nine>
      +      <left>Rewind</left>
      +      <right>FastForward</right>
      +      <up>Play</up>
      +      <down>Pause</down>
      +      <yellow>StepForward</yellow>
      +      <green>StepBack</green>
      +      <blue>CodecInfo</blue>
      +      <menu>OSD</menu>
      +      <start>OSD</start>
      +      <info>XBMC.ActivateWindow(PVROSDChannels)</info>
      +      <title>XBMC.ActivateWindow(PVROSDChannels)</title>
      +      <display>AspectRatio</display>
      +      <select>Info</select>
      +      <teletext>XBMC.ActivateWindow(Teletext)</teletext>
      +      <channelplus>SkipNext</channelplus>
      +      <channelminus>SkipPrevious</channelminus>
      +      <record>XBMC.PlayerControl(Record)</record>
      +    </remote>
      +  </FullscreenVideo>
      +  <FullscreenInfo>
      +    <remote>
      +      <back>FullScreen</back>
      +      <left>Rewind</left>
      +      <right>FastForward</right>
      +      <up>Play</up>
      +      <down>Pause</down>
      +      <yellow>StepForward</yellow>
      +      <green>StepBack</green>
      +      <display>AspectRatio</display>
      +      <info>CodecInfo</info>
      +      <select>Close</select>
      +      <menu>OSD</menu>
      +    </remote>
      +  </FullscreenInfo>
      +  <PlayerControls>
      +    <remote>
      +      <back>Close</back>
      +      <menu>Close</menu>
      +    </remote>
      +  </PlayerControls>
      +  <Visualisation>
      +    <universalremote>
      +       <obc151>XBMC.ActivateWindow(MyMusicPlaylist)</obc151>
      +    </universalremote>
      +    <remote>
      +      <red>FullScreen</red>
      +      <yellow>AnalogSeekForward</yellow>
      +      <green>AnalogSeekBack</green>
      +      <blue>CodecInfo</blue>
      +      <left>Rewind</left>
      +      <right>FastForward</right>
      +      <pageplus>SkipNext</pageplus>
      +      <pageminus>SkipPrevious</pageminus>
      +      <up>Play</up>
      +      <down>Pause</down>
      +      <info>XBMC.ActivateWindow(PVROSDChannels)</info>
      +      <back>XBMC.ActivateWindow(MyMusicPlaylist)</back>
      +      <select>Info</select>
      +      <menu>XBMC.ActivateWindow(MusicOSD)</menu>
      +      <start>XBMC.ActivateWindow(MusicOSD)</start>
      +    </remote>
      +  </Visualisation>
      +  <MusicOSD>
      +    <remote>
      +      <back>Close</back>
      +      <menu>Close</menu>
      +      <start>Close</start>
      +      <info>CodecInfo</info>
      +    </remote>
      +  </MusicOSD>
      +  <VisualisationSettings>
      +    <remote>
      +      <back>Close</back>
      +      <menu>Close</menu>
      +    </remote>
      +  </VisualisationSettings>
      +  <VisualisationPresetList>
      +    <remote>
      +      <back>Close</back>
      +      <menu>Close</menu>
      +    </remote>
      +  </VisualisationPresetList>
      +  <SlideShow>
      +    <remote>
      +      <zero>ZoomNormal</zero>
      +      <one>ZoomLevel1</one>
      +      <two>ZoomLevel2</two>
      +      <three>ZoomLevel3</three>
      +      <four>ZoomLevel4</four>
      +      <five>ZoomLevel5</five>
      +      <six>ZoomLevel6</six>
      +      <seven>ZoomLevel7</seven>
      +      <eight>ZoomLevel8</eight>
      +      <nine>ZoomLevel9</nine>
      +      <info>CodecInfo</info>
      +      <pageplus>ZoomIn</pageplus>
      +      <pageminus>ZoomOut</pageminus>
      +      <select>Rotate</select>
      +      <up>Pause</up>
      +      <down>Play</down>
      +      <back>PreviousMenu</back>
      +    </remote>
      +  </SlideShow>
      +  <ScreenCalibration>
      +    <remote>
      +      <select>NextCalibration</select>
      +      <enter>NextCalibration</enter>
      +      <zero>ResetCalibration</zero>
      +      <display>NextResolution</display>
      +      <xbox>NextResolution</xbox>
      +    </remote>
      +  </ScreenCalibration>
      +  <GUICalibration>
      +    <remote>
      +      <select>NextCalibration</select>
      +      <enter>NextCalibration</enter>
      +      <zero>ResetCalibration</zero>
      +    </remote>
      +  </GUICalibration>
      +  <SelectDialog>
      +    <remote>
      +      <back>Close</back>
      +    </remote>
      +  </SelectDialog>
      +  <VideoOSD>
      +    <remote>
      +      <back>PreviousMenu</back>
      +      <menu>Close</menu>
      +      <start>Close</start>
      +    </remote>
      +  </VideoOSD>
      +  <VideoMenu>
      +    <remote>
      +      <menu>OSD</menu>
      +      <back>PreviousMenu</back>
      +      <info>Info</info>
      +      <title>CodecInfo</title>
      +      <zero>Number0</zero>
      +      <one>Number1</one>
      +      <two>Number2</two>
      +      <three>Number3</three>
      +      <four>Number4</four>
      +      <five>Number5</five>
      +      <six>Number6</six>
      +      <seven>Number7</seven>
      +      <eight>Number8</eight>
      +      <nine>Number9</nine>
      +    </remote>
      +  </VideoMenu>
      +  <OSDVideoSettings>
      +    <remote>
      +      <back>Close</back>
      +      <menu>Close</menu>
      +      <start>Close</start>
      +    </remote>
      +  </OSDVideoSettings>
      +  <OSDAudioSettings>
      +    <remote>
      +      <back>Close</back>
      +      <menu>Close</menu>
      +      <start>Close</start>
      +    </remote>
      +  </OSDAudioSettings>
      +  <VideoBookmarks>
      +    <remote>
      +      <back>Close</back>
      +      <menu>Close</menu>
      +      <start>Close</start>
      +      <zero>Delete</zero>
      +    </remote>
      +  </VideoBookmarks>
      +  <MyVideoLibrary>
      +    <remote>
      +      <zero>Queue</zero>
      +      <clear>Delete</clear>
      +      <green>ToggleWatched</green>
      +      <yellow>Queue</yellow>
      +    </remote>
      +  </MyVideoLibrary>
      +  <MyVideoFiles>
      +    <remote>
      +      <zero>Queue</zero>
      +      <star>Queue</star>
      +      <blue>ContextMenu</blue>
      +      <green>ToggleWatched</green>
      +      <yellow>Queue</yellow>
      +    </remote>
      +  </MyVideoFiles>
      +  <MyPictures>
      +    <remote>
      +      <zero>Queue</zero>
      +      <star>Queue</star>
      +      <start>ContextMenu</start>
      +    </remote>
      +  </MyPictures>
      +  <MyVideoPlaylist>
      +    <remote>
      +      <back>Playlist</back>      <!-- Close playlist -->
      +      <clear>Delete</clear>
      +      <zero>Delete</zero>
      +    </remote>
      +  </MyVideoPlaylist>
      +  <VirtualKeyboard>
      +    <remote>
      +      <back>BackSpace</back>
      +      <star>Shift</star>
      +      <hash>Symbols</hash>
      +      <zero>Number0</zero>
      +      <one>Number1</one>
      +      <two>Number2</two>
      +      <three>Number3</three>
      +      <four>Number4</four>
      +      <five>Number5</five>
      +      <six>Number6</six>
      +      <seven>Number7</seven>
      +      <eight>Number8</eight>
      +      <nine>Number9</nine>
      +      <pageminus>CursorLeft</pageminus>
      +      <pageplus>CursorRight</pageplus>
      +    </remote>
      +  </VirtualKeyboard>
      +  <ContextMenu>
      +    <remote>
      +      <blue>Close</blue>
      +      <back>Close</back>
      +    </remote>
      +  </ContextMenu>
      +  <FileStackingDialog>
      +    <remote>
      +      <back>Close</back>
      +    </remote>
      +  </FileStackingDialog>
      +  <Scripts>
      +    <remote>
      +      <info>XBMC.ActivateWindow(ScriptsDebugInfo)</info>
      +    </remote>
      +  </Scripts>
      +  <ScriptsDebugInfo>
      +    <remote>
      +      <info>Info</info>      <!-- clears debug python info -->
      +    </remote>
      +  </ScriptsDebugInfo>
      +  <NumericInput>
      +    <remote>
      +      <zero>Number0</zero>
      +      <one>Number1</one>
      +      <two>Number2</two>
      +      <three>Number3</three>
      +      <four>Number4</four>
      +      <five>Number5</five>
      +      <six>Number6</six>
      +      <seven>Number7</seven>
      +      <eight>Number8</eight>
      +      <nine>Number9</nine>
      +      <back>BackSpace</back>
      +    </remote>
      +  </NumericInput>
      +  <Weather>
      +    <remote>
      +      <back>PreviousMenu</back>
      +    </remote>
      +  </Weather>
      +  <Settings>
      +    <remote>
      +      <back>PreviousMenu</back>
      +    </remote>
      +  </Settings>
      +  <MyPicturesSettings>
      +    <remote>
      +      <back>PreviousMenu</back>
      +    </remote>
      +  </MyPicturesSettings>
      +  <MyProgramsSettings>
      +    <remote>
      +      <back>PreviousMenu</back>
      +    </remote>
      +  </MyProgramsSettings>
      +  <MyWeatherSettings>
      +    <remote>
      +      <back>PreviousMenu</back>
      +    </remote>
      +  </MyWeatherSettings>
      +  <MyMusicSettings>
      +    <remote>
      +      <back>PreviousMenu</back>
      +    </remote>
      +  </MyMusicSettings>
      +  <SystemSettings>
      +    <remote>
      +      <back>PreviousMenu</back>
      +    </remote>
      +  </SystemSettings>
      +  <MyVideosSettings>
      +    <remote>
      +      <back>PreviousMenu</back>
      +    </remote>
      +  </MyVideosSettings>
      +  <NetworkSettings>
      +    <remote>
      +      <back>PreviousMenu</back>
      +    </remote>
      +  </NetworkSettings>
      +  <AppearanceSettings>
      +    <remote>
      +      <back>PreviousMenu</back>
      +    </remote>
      +  </AppearanceSettings>
      +  <Profiles>
      +    <remote>
      +      <back>PreviousMenu</back>
      +    </remote>
      +  </Profiles>
      +  <systeminfo>
      +    <remote>
      +      <back>PreviousMenu</back>
      +    </remote>
      +  </systeminfo>
      +  <shutdownmenu>
      +    <remote>
      +      <back>PreviousMenu</back>
      +    </remote>
      +  </shutdownmenu>
      +  <submenu>
      +    <remote>
      +      <back>PreviousMenu</back>
      +    </remote>
      +  </submenu>
      +  <MusicInformation>
      +    <remote>
      +      <back>Close</back>
      +    </remote>
      +  </MusicInformation>
      +  <MovieInformation>
      +    <remote>
      +      <back>Close</back>
      +    </remote>
      +  </MovieInformation>
      +  <LockSettings>
      +    <remote>
      +      <menu>Close</menu>
      +      <back>PreviousMenu</back>
      +    </remote>
      +  </LockSettings>
      +  <ProfileSettings>
      +    <remote>
      +      <menu>Close</menu>
      +      <back>PreviousMenu</back>
      +    </remote>
      +  </ProfileSettings>
      +  <PictureInfo>
      +    <remote>
      +      <skipplus>NextPicture</skipplus>
      +      <skipminus>PreviousPicture</skipminus>
      +      <info>Close</info>
      +      <back>Close</back>
      +    </remote>
      +  </PictureInfo>
      +  <Teletext>
      +    <remote>
      +      <zero>number0</zero>
      +      <one>number1</one>
      +      <two>number2</two>
      +      <three>number3</three>
      +      <four>number4</four>
      +      <five>number5</five>
      +      <six>number6</six>
      +      <seven>number7</seven>
      +      <eight>number8</eight>
      +      <nine>number9</nine>
      +      <red>Red</red>
      +      <green>Green</green>
      +      <yellow>Yellow</yellow>
      +      <blue>Blue</blue>
      +      <info>Info</info>
      +      <back>Close</back>
      +      <menu>Close</menu>
      +      <start>Close</start>
      +      <teletext>Close</teletext>
      +    </remote>
      +  </Teletext>
      +  <Favourites>
      +    <remote>
      +      <back>Close</back>
      +    </remote>
      +  </Favourites>
      +</keymap>
      +
      +
      +
      +
    2. +
    +
  4. +
+
+
+
+

7.30 dvd

+
+
+
+

7.30.1 tasks

+
+
+
    +
  • install libdvd-pkg, allow programs to eject optical media
    +
    +
    +
    ---
    +# file: roles/dvd/tasks/main.yml
    +
    +#- name: preconfigure libdvd-pkg
    +#  shell: |
    +#    echo 'libdvd-pkg libdvd-pkg/post-invoke_hook-install boolean true' | debconf-set-selections
    +#    echo 'libdvd-pkg libdvd-pkg/build boolean true' | debconf-set-selections
    +
    +- name: apt | install libdvd-pkg
    +  apt:
    +    name: '{{ item }}'
    +    state: present
    +    install_recommends: no
    +  with_items:
    +    - 'libdvd-pkg'
    +
    +- name: configure package libdvd-pkg
    +  debconf:
    +    name: 'libdvd-pkg'
    +    question: '{{ item }}'
    +    vtype: boolean
    +    value: true
    +  with_items:
    +      - 'libdvd-pkg/post-invoke_hook-install'
    +      - 'libdvd-pkg/build boolean'
    +  notify: ['Reconfigure unattended upgrades with dpkg']
    +
    +- name: change udev rule to allow KODI to eject optical disks
    +  shell: sed 's/--lock-media //' /lib/udev/rules.d/60-cdrom_id.rules > /etc/udev/rules.d/60-cdrom_id.rules
    +  args:
    +    creates: /etc/udev/rules.d/60-cdrom_id.rules
    +
    +
    +
    +
  • +
+
+
+
+

7.31 template-test

+
+
+
---
+
+- name: show vars
+  debug: 
+    var: '{{ system }}'
+
+- name: test templates
+  template:
+    src: templates/test.j2
+    dest: /tmp/test.txt
+
+
+
+
{{ ansible_managed | comment }}
+
+Section "ServerLayout"
+    Identifier     "Layout0"
+    Screen      0  "Screen0"
+    {% if system.x11.dualhead.enabled %}
+    Screen      1  "Screen1" RightOf "Screen0"
+    {% endif %}
+    InputDevice    "Keyboard0" "CoreKeyboard"
+    InputDevice    "Mouse0" "CorePointer"
+EndSection
+
+Section "InputDevice"
+    # generated from default
+    Identifier     "Mouse0"
+    Driver         "mouse"
+    Option         "Protocol" "auto"
+    Option         "Device" "/dev/psaux"
+    Option         "Emulate3Buttons" "no"
+    Option         "ZAxisMapping" "4 5"
+EndSection
+
+# ignore devices with eventlircd tag 
+# ENV{ID_INPUT.tags}+="eventlircd"
+# must be set by an udev rule
+Section "InputClass"
+    Identifier "ignore eventlircd devices"
+    MatchTag "eventlircd"
+    Option "Ignore" "True"
+EndSection
+
+
+
+Section "InputDevice"
+    # generated from default
+    Identifier     "Keyboard0"
+    Driver         "kbd"
+EndSection
+
+
+Section "Monitor"
+    Identifier     "Monitor0"
+    VendorName     "Unknown"
+    ModelName      "Unknown"
+{% if system.x11.display.0.default == "VGA2Scart_4_3" or system.x11.display.0.default == "VGA2Scart_16_9" %}
+    HorizSync       14-17
+    VertRefresh     49-61
+    {% if system.x11.display.0.default == "VGA2Scart_4_3" %}
+    Modeline "VGA2Scart_4_3" 13.875 720 744 808 888 576 580 585 625 -HSync -Vsync interlace
+    {% elif system.x11.display.0.default == "VGA2Scart_16_9" %}
+    Modeline "VGA2Scart_16_9" 19 1024 1032 1120 1216 576 581 586 625 -Hsync -Vsync interlace
+    {% endif %}
+{% endif %}
+    Option         "DPMS"
+    Option         "ExactModeTimingsDVI" "True"
+EndSection
+
+
+{% if system.x11.dualhead.enabled == "1" %}
+Section "Monitor"
+    Identifier     "Monitor1"
+    VendorName     "Unknown"
+    ModelName      "Unknown"
+{% if system.x11.display.1.default in ("VGA2Scart_4_3",  "VGA2Scart_16_9") %}
+    HorizSync       14-17
+    VertRefresh     49-61
+    {% if system.x11.display.1.default == "VGA2Scart_4_3" %}
+    Modeline "VGA2Scart_4_3" 13.875 720 744 808 888 576 580 585 625 -HSync -Vsync interlace
+    {% elif system.x11.display.1.default == "VGA2Scart_16_9" %}
+    Modeline "VGA2Scart_16_9" 19 1024 1032 1120 1216 576 581 586 625 -Hsync -Vsync interlace
+    {% endif %}
+    Option         "DPMS"
+    Option         "ExactModeTimingsDVI" "True"
+{% endif %}
+EndSection
+{% endif %}
+
+Section "Device"
+    Identifier     "Device0"
+{% if system.hardware.nvidia.detected %}
+    Driver         "nvidia"
+    VendorName     "NVIDIA Corporation"
+{% endif %}
+    Screen          0
+    Option         "DPI" "100x100"
+{% if system.hardware.nvidia.busid %}
+    BusID          "PCI: {{ system.hardware.nvidia.busid }}"
+{% endif %}
+    Option         "NoLogo" "True"
+    Option         "UseEvents" "True"
+    Option         "TripleBuffer" "False"
+    Option         "AddARGBGLXVisuals" "True"
+    Option         "TwinView" "0"
+    Option         "DynamicTwinView" "0"
+    Option         "OnDemandVBlankinterrupts" "on"
+    Option         "FlatPanelProperties" "Scaling = Native"
+EndSection
+
+{% if system.x11.dualhead.enabled == "1" %}
+Section "Device"
+    Identifier     "Device1"
+    {% if system.hardware.nvidia.detected %}
+    Driver         "nvidia"
+    VendorName     "NVIDIA Corporation"
+    {% endif %}
+    Screen          1
+    {% if system.hardware.nvidia.busid %}
+    BusID          "PCI: {{ system.hardware.nvidia.busid }}"
+    {% endif %}
+    Option         "NoLogo" "True"
+    Option         "UseEvents" "True"
+    Option         "TripleBuffer" "False"
+    Option         "AddARGBGLXVisuals" "True"
+    Option         "TwinView" "0"
+    Option         "DynamicTwinView" "0"
+EndSection
+{% endif %}
+
+
+Section "Screen"
+    Identifier     "Screen0"
+    Device         "Device0"
+    Monitor        "Monitor0"
+    DefaultDepth    24
+    SubSection     "Display"
+        Depth       24
+{% if system.x11.display.0.default is defined and system.x11.display.0.default %}
+        Modes      "{{ system.x11.display.0.default }}"{% for mode in system.x11.display.0.mode %}{% if mode != system.x11.display.0.default %} "{{ mode }}"{% endif %}{% endfor %}
+
+{% elif system.hardware.nvidia.detected == 1 %}
+        Modes      "nvidia-auto-select"
+{% endif %}
+    EndSubSection
+{% if system.x11.display.0.default or system.x11.default %}
+    {% if system.x11.display.0.device is definded and system.x11.display.0.device %}
+    Option         "ConnectedMonitor" {{ system.x11.display.0.device }}
+    {% else %}
+    Option         "ConnectedMonitor" {{ system.x11.default }}
+    {% endif %}
+    #     Option         "ConnectedMonitor" "<?cs if:(?system.x11.display.0.device) ?><?cs call:fix_display_name(system.x11.display.0.device) ?><?cs else ?><?cs var:system.x11.default ?><?cs /if ?><?cs if:(?system.x11.dualhead.enabled && system.x11.dualhead.enabled == 1) ?>, <?cs call:fix_display_name(system.x11.display.1.device) ?><?cs /if ?>"
+    #Option         "ConnectedMonitor"
+    "<?cs if:(?system.x11.display.0.device) ?>
+          <?cs call:fix_display_name(system.x11.display.0.device) ?>
+     <?cs else ?>
+          <?cs var:system.x11.default ?>
+     <?cs /if ?>
+     <?cs if:(?system.x11.dualhead.enabled && system.x11.dualhead.enabled == 1) ?>, <?cs call:fix_display_name(system.x11.display.1.device) ?><?cs /if ?>"
+#     Option         "UseDisplayDevice" "<?cs if:(?system.x11.display.0.device) ?><?cs call:fix_display_name(system.x11.display.0.device) ?><?cs else ?><?cs var:system.x11.default ?><?cs /if ?>"
+# <?cs /if ?>
+# <?cs if:(?system.hardware.nvidia.0.edid && system.hardware.nvidia.0.edid == "1") ?>
+#     Option         "CustomEDID" "<?cs call:fix_display_name(system.x11.display.0.device) ?>:/etc/X11/edid.0.yavdr"
+# <?cs /if ?>
+# <?cs if:(system.hardware.nvidia.detected == 1 && ?system.x11.display.0.device) ?>
+#     Option          "MetaModes" "<?cs call:fix_display_name(system.x11.display.0.device) ?>: <?cs var:system.x11.display.0.default ?> { ViewPortIn=<?cs var:system.x11.display.0.viewport.in.x ?>x<?cs var:system.x11.display.0.viewport.in.y ?>, ViewPortOut=<?cs var:system.x11.display.0.viewport.out.x ?>x<?cs var:system.x11.display.0.viewport.out.y ?>+<?cs var:system.x11.display.0.viewport.out.plusx ?>+<?cs var:system.x11.display.0.viewport.out.plusy ?> }"
+# <?cs each:mode = system.x11.display.0.mode ?><?cs if:(mode != system.x11.display.0.default) ?>
+#     Option          "MetaModes" "<?cs call:fix_display_name(system.x11.display.0.device) ?>: <?cs var:mode ?> { ViewPortIn=<?cs var:system.x11.display.0.viewport.in.x ?>x<?cs var:system.x11.display.0.viewport.in.y ?>, ViewPortOut=<?cs var:system.x11.display.0.viewport.out.x ?>x<?cs var:system.x11.display.0.viewport.out.y ?>+<?cs var:system.x11.display.0.viewport.out.plusx ?>+<?cs var:system.x11.display.0.viewport.out.plusy ?> }"<?cs /if ?><?cs /each ?> 
+{% endif %}
+EndSection
+
+{% if system.x11.dualhead.enabled == "1" %}
+Section "Screen"
+
+     Identifier     "Screen1"
+     Device         "Device1"
+     Monitor        "Monitor1"
+     DefaultDepth    24
+     SubSection     "Display"
+         Depth       24
+{% if system.x11.display.0.default is defined and system.x11.display.0.default %}
+         Modes      "{{ system.x11.display.1.default }}"{% for mode in system.x11.display.1.mode %}{% if mode != system.x11.display.1.default %} "{{ mode }}"{% endif %}{% endfor %}
+
+{% elif system.hardware.nvidia.detected == "1" %}
+         Modes      "nvidia-auto-select"
+{% endif %}
+      EndSubSection
+
+# <?cs if:(?system.x11.display.1.default && system.x11.display.1.default != "" && system.x11.display.1.default != "disabled") ?>
+#     Option         "UseDisplayDevice" "<?cs call:fix_display_name(system.x11.display.1.device) ?>"
+# <?cs /if ?>
+# <?cs if:(?system.hardware.nvidia.1.edid && system.hardware.nvidia.1.edid == "1") ?>
+#     Option         "CustomEDID" "<?cs call:fix_display_name(system.x11.display.1.device) ?>:/etc/X11/edid.1.yavdr"
+# <?cs /if ?>
+# <?cs if:(system.hardware.nvidia.detected == 1 && ?system.x11.display.1.device) ?>
+#     Option          "MetaModes" "<?cs call:fix_display_name(system.x11.display.1.device) ?>: <?cs var:system.x11.display.1.default ?> { ViewPortIn=<?cs var:system.x11.display.1.viewport.in.x ?>x<?cs var:system.x11.display.1.viewport.in.y ?>, ViewPortOut=<?cs var:system.x11.display.1.viewport.out.x ?>x<?cs var:system.x11.display.1.viewport.out.y ?>+<?cs var:system.x11.display.1.viewport.out.plusx ?>+<?cs var:system.x11.display.1.viewport.out.plusy ?> }"
+# <?cs each:mode = system.x11.display.1.mode ?><?cs if:(mode != system.x11.display.1.default) ?>
+#     Option          "MetaModes" "<?cs call:fix_display_name(system.x11.display.1.device) ?>: <?cs var:mode ?> { ViewPortIn=<?cs var:system.x11.display.1.viewport.in.x ?>x<?cs var:system.x11.display.1.viewport.in.y ?>, ViewPortOut=<?cs var:system.x11.display.1.viewport.out.x ?>x<?cs var:system.x11.display.1.viewport.out.y ?>+<?cs var:system.x11.display.1.viewport.out.plusx ?>+<?cs var:system.x11.display.1.viewport.out.plusy ?> }"<?cs /if ?><?cs /each ?>
+# <?cs /if ?>
+EndSection
+{% endif %}
+
+{% if not system.x11.use_compositing %}
+Section "Extensions"
+# if not open-gl OSD is needed (e.g. for vdr-sxfe):
+    Option         "Composite" "Disable"
+EndSection
+{% endif %}
+
+
+
+
foo:
+  - bar
+  - baz
+  - spam
+
+system:
+  hardware:
+    nvidia:
+      detected: "1"
+      busid: "000:2304:234"
+  x11:
+    dualhead:
+      enabled: "0"
+    display:
+      0:
+        mode:
+          - "1920x1080_50"
+        default: "nvidia-auto"
+
+      1:
+        mode:
+          - "1280x720_60"
+
+
+
+
+
+

7.32 wakeup

+
+
+
+

7.32.1 defaults

+
+
+
---
+# file roles/wakeup/defaults/main.yml
+wakeup_method: "acpiwakeup"
+
+
+
+
+
+

7.32.2 tasks

+
+
+
---
+# file roles/wakeup/tasks/main.yml
+
+- name: install and configure vdr-addon-acpiwakeup
+  apt:
+    name: vdr-addon-acpiwakeup
+    state: present
+  when: wakeup_method == "acpiwakeup"
+      
+- name: expand template for /etc/vdr/vdr-addon-acpiwakeup.conf
+  template:
+    src: templates/vdr-addon-acpiwakeup.conf.j2
+    dest: /etc/vdr/vdr-addon-acpiwakeup.conf
+
+
+
+
+
+
+

7.32.3 templates

+
+
+
{{ ansible_managed | comment }}
+
+# Activate/deactivate ACPIWakeup with yes/no:
+ACPI_ENABLED="{% if wakeup_method == 'acpiwakeup' %}yes{% else %}no{% endif %}"
+
+# How many minutes should the machine wake up before the timer starts:
+ACPI_START_AHEAD=5
+
+# If you want your VDR machine to wakeup in regular intervals (i.e. for
+# updating EPG data), specify the days of the week and the wakeup time.
+#
+# Days of the week for regular wakeup (not set=Disabled, 1=Monday...7=Sunday)
+# ACPI_REGULAR_DAYS="1 2 3 4 5 6 7"
+
+# Wakeup time
+#ACPI_REGULAR_TIME=01:00  # HH:MM
+
+
+
+
+
+
+ +
+

7.33 grub-config

+
+
+
+

7.33.1 default variables

+
+
+
system:
+  shutdown: poweroff
+grub:
+  timeout: 0
+  boot_options: quiet nosplash
+
+
+
+
+
+

7.33.2 tasks

+
+
+
---
+
+- name: custom grub configuration for timeout and reboot halt
+  template:
+    src: templates/50_custom.j2
+    dest: /etc/grub.d/50_custom
+    mode: '0775'
+  notify: [ 'Update GRUB' ]
+
+# TODO: add special case if plymouth is used
+- name: let the system boot quietly
+  lineinfile:
+      dest: /etc/default/grub
+      state: present
+      regexp: '^(GRUB_CMDLINE_LINUX_DEFAULT=")'
+      line: '\1{{ grub.boot_options}}"'
+      backrefs: yes
+  notify: [ 'Update GRUB' ]
+
+
+
+
+
+

7.33.3 templates

+
+
+
#!/bin/sh
+exec tail -n +3 $0
+
+# This file is configured by the ansible configuration for yaVDR
+
+{% if system.shutdown is defined and system.shutdown == 'reboot' %}
+menuentry "PowerOff" {
+    halt
+}
+{% endif %}
+
+if [ "${recordfail}" = 1 ]; then
+    set timeout={{ 3 if grub.timeout < 3 else grub.timeout }}
+else
+    set timeout={{ grub.timeout if grub.timeout is defined else 0 }}
+fi
+
+
+
+
+
+

7.33.4 handlers

+
+
+
---
+
+- name: Update GRUB
+  command: update-grub
+  failed_when: ('error' in grub_register_update.stderr)
+  register: grub_register_update
+
+  # TODO: Do we need to use grub-set-default?
+  # https://github.com/yavdr/yavdr-utils/blob/master/events/actions/update-grub
+
+
+
+
+
+
+
+

8 Modules

+
+

+This section contains custom modules for the yaVDR Playbooks. They are used to collect facts about the system and configure applications and daemons. +

+
+
+

8.1 hardware_facts.py

+
+
+
# This Module collects the vendor- and device ids for USB- and PCI(e)-devices and currently loaded kernel modules.
+DOCUMENTATION = '''
+  ---
+  module: hardware_facts
+  short_description: collects facts for kernel modules, usb and pci devices
+  description:
+       - This Module collects the vendor- and device ids for USB- and PCI(e)-devices and
+         currently loaded kernel modules.
+  options:
+      usb:
+          required: False
+          default: True
+          description:
+            - return a list of vendor- and device ids for usb devices in '04x:04x' notation
+
+    pci:
+        required: False
+        default: True
+        description:
+          - return a list of vendor- and device ids for pci devices in '04x:04x' notation
+
+    modules:
+        required: False
+        default: True
+        description:
+          - return a list of currently loaded kernel modules
+
+    gpus:
+        required: False
+        default: True
+        description:
+          - return a list of devices of the pci gpu class (0x030000)
+
+    acpi_power_modes:
+        required: False
+        default: True
+        description:
+          - return a list of supported acpi power saving modes
+notes:
+   - requres python-pyusb and python-kmodpy
+requirements: [ ]
+author: "Alexander Grothe <seahawk1986@gmx.de>"
+'''
+
+EXAMPLES = '''
+- name: get information about usb and pci hardware and loaded kernel modules
+  hardware_facts:
+    usb: True
+    pci: True
+    modules: True
+    acpi_power_modes: True
+- debug:
+    var: usb
+- debug:
+    var: pci
+- debug:
+    var: modules
+- debug:
+    var: gpus
+'''
+
+import glob
+import json
+import os
+import sys
+import usb.core
+from collections import namedtuple
+
+import kmodpy
+from ansible.module_utils.basic import *
+
+
+PCIDevice = namedtuple("PCIDevice", 'idVendor idProduct idClass pciPath')
+
+vendor_dict = {
+    0x10de: 'nvidia',
+    0x8086: 'intel',
+    0x1002: 'amd',
+    0x80ee: 'virtualbox',
+    }
+
+def get_pci_devices():
+    for device in glob.glob('/sys/devices/pci*/*:*:*/*:*:*/'):
+        try:
+            with open(os.path.join(device, 'device')) as d:
+                product_id = int(d.read().strip(), 16)
+            with open(os.path.join(device, 'vendor')) as d:
+                vendor_id = int(d.read().strip(), 16)
+            with open(os.path.join(device, 'class')) as d:
+                class_id = int(d.read().strip(), 16)
+            yield PCIDevice(idVendor=vendor_id, idProduct=product_id, idClass=class_id, pciPath=device)
+        except IOError:
+            pass
+
+def format_device_list(iterator):
+    return ["{:04x}:{:04x}".format(d.idVendor, d.idProduct) for d in iterator]
+
+def format_gpu_device_list(iterator):
+    def get_entries(iterator):
+        for d in iterator:
+            if d.idClass == 0x030000:
+                yield {"VendorName": vendor_dict.get(d.idVendor, "unknown"),
+                       "VendorID": d.idVendor, "ProductID": d.idProduct}
+    return [entry for entry in get_entries(iterator)]
+
+def list_acpi_power_modes():
+    acpi_power_modes = []
+    try:
+        with open('/sys/power/state') as f:
+            acpi_power_modes = [l for l in f.readline().split()]
+    except IOError:
+        pass
+    return acpi_power_modes
+
+arg_specs = {
+    'usb': dict(default=True, type='bool', required=False),
+    'pci': dict(default=True, type='bool', required=False),
+    'modules': dict(default=True, type='bool', required=False),
+    'gpus': dict(default=True, type='bool', required=False),
+    'acpi_power_modes': dict(default=True, type='bool', required=False),
+    }
+
+
+def main():
+    module = AnsibleModule(argument_spec=arg_specs, supports_check_mode=True,)
+    collect_usb = module.params['usb']
+    collect_pci = module.params['pci']
+    collect_modules = module.params['modules']
+    collect_gpus = module.params['gpus']
+    collect_acpi_power_modes = module.params['acpi_power_modes']
+
+    usb_devices = []
+    pci_devices = []
+    modules = []
+    gpus = []
+    nvidia_detected = False
+    intel_detected = False
+    amd_detected = False
+    virtualbox_detected = False
+    acpi_power_modes = []
+
+    if collect_usb:
+        usb_devices = format_device_list(usb.core.find(find_all=True))
+
+    if collect_pci:
+        pci_devices = format_device_list(get_pci_devices())
+
+    if collect_modules:
+        k = kmodpy.Kmod()
+        modules = [m[0] for m in k.loaded()]
+
+    if collect_gpus:
+        gpus = format_gpu_device_list(get_pci_devices())
+        nvidia_detected = any((True for gpu in gpus if gpu['VendorName'] == 'nvidia'))
+        intel_detected = any((True for gpu in gpus if gpu['VendorName'] == 'intel'))
+        amd_detected = any((True for gpu in gpus if gpu['VendorName'] == 'amd'))
+        virtualbox_detected = any((True for gpu in gpus if gpu['VendorName'] == 'virtualbox'))
+
+    if collect_acpi_power_modes:
+        acpi_power_modes = list_acpi_power_modes()
+
+    data = {'usb': usb_devices, 'pci': pci_devices, 'modules': modules, 'gpus': gpus,
+            'acpi_power_modes': acpi_power_modes, 'nvidia_detected': nvidia_detected,
+            'intel_detected': intel_detected, 'amd_detected': amd_detected,
+            'virtualbox_detected': virtualbox_detected}
+    module.exit_json(changed=False, ansible_facts=data, msg=data)
+
+
+if __name__ == '__main__':  
+    main()
+
+
+
+
+
+

8.2 satip_facts.py

+
+
+
DOCUMENTATION = '''
+---
+module: hardware_facts
+short_description: "check if at least one SAT>IP server responds on the network"
+description:
+     - This script sends a multicast message and awaits responses by Sat>IP servers.
+       Returns a list of detected SAT>IP servers with their name and capabilites.
+'''
+EXAMPLES = '''
+- name: "detect SAT>IP Server on the network"
+  action: satip_facts
+
+- debug:
+    var: satip_devices
+'''
+
+import json
+import socket
+import sys
+import time
+import xml.etree.ElementTree as ET
+import requests
+from contextlib import contextmanager
+from ansible.module_utils.basic import *
+
+SSDP_BIND = "0.0.0.0"
+SSDP_ADDR = "239.255.255.250"
+SSDP_PORT = 1900
+# SSDP_MX = max delay for server response
+# a value of 2s is recommended by the SAT>IP specification 1.2.2
+SSDP_MX = 2
+SSDP_ST = "urn:ses-com:device:SatIPServer:1"
+
+ssdpRequest = "\r\n".join((
+    "M-SEARCH * HTTP/1.1",
+    "HOST: %s:%d" % (SSDP_ADDR, SSDP_PORT),
+    "MAN: \"ssdp:discover\"",
+    "MX: %d" % (SSDP_MX),
+    "ST: %s" % (SSDP_ST),
+    "\r\n"))
+
+@contextmanager
+def socket_manager(*args, **kwargs):
+    """provide a context manager for socket"""
+    sock = socket.socket(*args, **kwargs)
+    sock.setblocking(False)
+    sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 2)
+    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+    try:
+        sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
+    except socket.error:
+        pass
+    sock.settimeout(SSDP_MX + 0.5)
+    sock.bind((SSDP_BIND, SSDP_PORT))
+    try:
+        yield sock
+    finally:
+        sock.close()
+
+
+def parse_satip_xml(data):
+    """ Parse SAT>IP XML data.
+    Args:
+        data (str): XML input data..
+    Returns:
+        dict: Parsed SAT>IP device name and frontend information.
+    """
+    result = {'name': '', 'frontends': {}}
+    if data:
+        root = ET.fromstring(data)
+        name = root.find('.//*/{urn:schemas-upnp-org:device-1-0}friendlyName')
+        result['name'] = name.text
+        satipcap = root.find('.//*/{urn:ses-com:satip}X_SATIPCAP')
+        if satipcap is None:
+            raise ValueError("Invalid SAT>IP device description")
+        caps = {}
+        for system in satipcap.text.split(","):
+            cap = system.split("-")
+            if cap:
+                count = int(cap[1])
+                if cap[0] in caps:
+                    count = count + caps[cap[0]]
+                caps[cap[0]] = count
+        result['frontends'] = caps
+    return result
+
+
+def main():
+    description_urls = []
+    device_list = []
+    module = AnsibleModule(argument_spec={}, supports_check_mode=True,)
+    with socket_manager(socket.AF_INET, socket.SOCK_DGRAM) as sock:
+        # according to Sat>IP Specification 1.2.2, p. 20
+        # a client should send three requests within 100 ms with a ttl of 2
+
+        for _ in range(3):
+            sock.sendto(ssdpRequest, (SSDP_ADDR, SSDP_PORT))
+            time.sleep(0.03)
+        try:
+            response = sock.recv(1024)
+            if response and "SERVER:" in response:
+                for line in response.splitlines():
+                    if "LOCATION" in line:
+                        url = line.split()[-1].strip()
+                        if url not in description_urls:
+                            description_urls.append(url)
+                            info = requests.get(url, timeout=2)
+                            device_list.append(parse_satip_xml(info.text))
+            else:
+                raise ValueError('No satip server detected')
+        except (socket.timeout, ValueError, ET.ParseError):
+            pass
+
+    module.exit_json(changed=False, ansible_facts={'satip_devices': device_list})
+
+if __name__ == '__main__':
+    main()
+
+
+
+
+
+

8.3 xrandr_facts.py

+
+
    +
  • [ ] support multiple screens (-d :0.0 .. :0.n)
  • +
+ +
+
from __future__ import print_function
+import ast
+import binascii
+import csv
+import re
+import subprocess
+from collections import namedtuple
+
+from ansible.module_utils.basic import *
+
+DOCUMENTATION = '''
+---
+module: xrandr_facts
+short_description: "gather facts about connected monitors and available modelines"
+description:
+     - This module needs a running x-server on a given display in order to successfully call xrandr.
+       Returns the dictionary "xrandr", wich contains all screens with output states, connected displays,
+       EDID info and their modes and a recommendation for the best fitting tv mode.
+options:
+    display:
+        required: False
+        default: ":0"
+        description:
+          - the DISPLAY variable to use when calling xrandr
+    preferred_outputs:
+        required: False
+        default: ["HDMI", "DP", "DVI", "VGA", "TV"]
+        description:
+          - ranking of the preferred display connectors
+    preferred_refreshrates:
+        required: False
+        default: ["50", "60", "75", "30", "25"]
+        description:
+          - ranking of the preferred display refreshrate
+    preferred_resolutions:
+        required: False
+        default: ["7680x4320", "3840x2160", "1920x1080", "1280x720", "720x576"]
+        description:
+           - ranking of the preferred display resolutions
+    write_edids:
+        required: False
+        default: True
+        description:
+           - write edid data to /etc/X11/edid.{connector}.bin
+'''
+EXAMPLES = '''
+- name: "collect facts for connected displays"
+  action: xserver_facts
+    display: ":0"
+
+- debug:
+    var: xrandr
+
+- debug:
+    var: xorg
+'''
+
+ARG_SPECS = {
+    'display': dict(default=":0", type='str', required=False),
+    'preferred_outputs': dict(
+        default=["HDMI", "DP", "DVI", "VGA", "TV"], type='list', required=False),
+    'preferred_refreshrates': dict(
+        default=[50, 60, 75, 30, 25], type='list', required=False),
+    'preferred_resolutions': dict(
+        default=[
+            "7680x4320", "3840x2160", "1920x1080", "1280x720", "720x576"],
+        type='list', required=False),
+    'write_edids': dict(default=True, type='bool', required=False),
+    }
+
+SCREEN_REGEX = re.compile("^(?P<screen>Screen\s\d+:)(?:.*)")
+CONNECTOR_REGEX = re.compile(
+    "^(?P<connector>.*-\d+)\s(?P<connection_state>connected|disconnected)\s(?P<primary>primary)?")
+MODE_REGEX = re.compile("^\s+(?P<resolution>\d{3,}x\d{3,}).*")
+
+Mode = namedtuple('Mode', ['connection', 'resolution', 'refreshrate'])
+
+def check_for_screen(line):
+    """check line for screen information"""
+    match = re.match(SCREEN_REGEX, line)
+    if match:
+        return match.groupdict()['screen']
+
+def check_for_connection(line):
+    """check line for connection name and state"""
+    match = re.match(CONNECTOR_REGEX, line)
+    connector = None
+    is_connected = False
+    if match:
+        match = match.groupdict()
+        connector = match['connector']
+        is_connected = True if match['connection_state'] == 'connected' else False
+    return connector, is_connected
+
+def get_indentation(line):
+    """return the number of leading whitespace characters"""
+    return len(line) - len(line.lstrip())
+
+def sort_mode(mode):
+    """rate modes by several criteria"""
+    connection_score = 0
+    rrate_score = 0
+    resolution_score = 0
+    preferred_rrates = module.params['preferred_refreshrates']
+    # [50, 60]
+    preferred_resolutions = module.params['preferred_resolutions']
+    # ["7680x4320", "3840x2160", "1920x1080", "1280x720", "720x576"]
+    preferred_outputs = module.params['preferred_outputs']
+    # ["HDMI", "DP", "DVI", "VGA"]
+    if mode.refreshrate in preferred_rrates:
+        rrate_score = len(preferred_rrates) - preferred_rrates.index(mode.refreshrate)
+    if mode.resolution in preferred_resolutions:
+        resolution_score = len(preferred_resolutions) - preferred_resolutions.index(mode.resolution)
+    x_resolution, y_resolution = (int(n) for n in  mode.resolution.split('x'))
+    connection = mode.connection.split('-')[0]
+    if connection in preferred_outputs:
+        connection_score = len(preferred_outputs) - preferred_outputs.index(connection)
+    return (rrate_score, resolution_score, x_resolution, y_resolution, connection_score)
+
+def parse_xrandr_verbose(iterator):
+    """parse the output of xrandr --verbose using an iterator delivering single lines"""
+    xorg = {}
+    is_connected = False
+    for line in iterator:
+        if line.startswith('Screen'):
+            screen = check_for_screen(line)
+            xorg[screen] = {}
+        elif 'connected' in line:
+            connector, is_connected = check_for_connection(line)
+            xorg[screen][connector] = {
+                'is_connected': is_connected,
+                'EDID': '',
+                'modes': {},
+                'preferred': '',
+                'current': '',
+                'auto': '',
+                }
+        elif is_connected and 'EDID:' in line:
+            edid_str = ""
+            outer_indentation = get_indentation(line)
+            while True:
+                line = next(iterator)
+                if get_indentation(line) > outer_indentation:
+                    edid_str += line.strip()
+                else:
+                    break
+            xorg[screen][connector]['EDID'] = edid_str
+        elif is_connected and "MHz" in line and not "Interlace" in line:
+            match = re.match(MODE_REGEX, line)
+            if match:
+                match = match.groupdict()
+                preferred = bool("+preferred" in line)
+                current = bool("*current" in line)
+
+                while True:
+                    line = next(iterator)
+                    if line.strip().startswith('v:'):                        
+                        refresh_rate = ast.literal_eval(line.split()[-1][:-2])
+                        rrate = int(round(refresh_rate))
+                        if xorg[screen][connector]['modes'].get(match['resolution']) is None:
+                            xorg[screen][connector]['modes'][match['resolution']] = []
+                        if rrate not in xorg[screen][connector]['modes'][match['resolution']]:
+                            xorg[screen][connector]['modes'][match['resolution']].append(rrate)
+                        if preferred:
+                            xorg[screen][connector]['preferred'] = "{}_{}".format(
+                                match['resolution'], rrate)
+                        if current:
+                            xorg[screen][connector]['current'] = "{}_{}".format(
+                                match['resolution'], rrate)
+                        break
+    return xorg
+
+def parse_edid_data(edid):
+    vendor = "Unknown"
+    model = "Unknown"
+    data = subprocess.check_output("parse-edid < {}".format(edid), shell=True, universal_newlines=True)
+    for line in data.splitlines():
+        if "VendorName" in line:
+            vendor = line.strip().split('"')[1]
+        if "ModelName" in line:
+            model =  line.strip().split('"')[1]
+    return vendor, model
+
+def collect_nvidia_data():
+    BusID_RE = re.compile((
+        '(?P<domain>[0-9a-fA-F]+)'
+        ':'
+        '(?P<bus>[0-9a-fA-F]+)'
+        ':'
+        '(?P<device>[0-9a-fA-F]+)'
+        '\.'
+        '(?P<function>[0-9a-fA-F]+)'
+     ))    
+    try:
+        data = subprocess.check_output(["nvidia-smi", "--query-gpu=name,pci.bus_id", "--format=csv", "-i0"],
+                                universal_newlines=True)
+    except subprocess.CalledProcessError:
+        pass
+    except OSError:
+        # nvidia-smi is not installed
+        pass
+    else:
+        for row in csv.DictReader(data.splitlines(), delimiter=',', skipinitialspace=True):
+            name = row['name']
+            bus_id = row['pci.bus_id']
+            # pci.bus_id structure as reported by nvidia-smi: "domain:bus:device.function", in hex.
+            match = BusID_RE.search(bus_id)
+            if match:
+                domain, bus, device, function = (int(n, 16) for n in match.groups())
+                bus_id = "PCI:{:d}@{:d}:{:d}:{:d}".format(bus, domain, device, function)
+                return name, bus_id
+    raise ValueError
+
+
+def output_data(data, write_edids=True):
+    if data:
+        modes = []
+        for _, screen_data in data.items():
+            for connector, connection_data in screen_data.items():
+                if connection_data.get('EDID') and write_edids:
+                    with open('/etc/X11/edid.{}.bin'.format(connector), 'wb') as edid:
+                        edid.write(binascii.a2b_hex(connection_data['EDID']))
+                for resolution, refreshrates in connection_data['modes'].items():
+                    for refreshrate in refreshrates:
+                        modes.append(Mode(connector, resolution, refreshrate))
+        if modes:
+            result = {}
+            try:
+                gpu_name, bus_id = collect_nvidia_data()
+            except ValueError:
+                gpu_name = None
+                bus_id = None
+
+            def create_entry(my_dict, name, connector, resolution, refreshrate, vendor, model):
+                my_dict[name] = {
+                    'connector': connector,
+                    'resolution': resolution,
+                    'refreshrate': refreshrate,
+                    'edid': '/etc/X11/edid.{}.bin'.format(connector),
+                    'mode': "{}_{}".format(resolution, refreshrate),
+                    'vendor': vendor,
+                    'model': model,
+                }
+                if gpu_name and bus_id:
+                    result[name]['gpu_name'] = gpu_name
+                    result[name]['bus_id'] = bus_id
+
+            connector_0, resolution_0, refreshrate_0 = max(modes, key=sort_mode)[:3]
+            vendor_0, model_0 = parse_edid_data('/etc/X11/edid.{}.bin'.format(connector_0))
+            create_entry(result, 'primary', connector_0, resolution_0, refreshrate_0, vendor_0, model_0)
+
+            # check if additional monitors exist
+            other_modes = [mode for mode in modes if mode[0] != connector_0]
+            if other_modes:
+                connector_1, resolution_1, refreshrate_1 = max(other_modes, key=sort_mode)[:3]
+                vendor_1, model_1 = parse_edid_data('/etc/X11/edid.{}.bin'.format(connector_1))
+                create_entry(result, 'secondary', connector_1, resolution_1, refreshrate_1, vendor_1, model_1)
+
+    #print(json.dumps(data, sort_keys=True, indent=4))
+    module.exit_json(changed=True if write_edids else False, ansible_facts={'xrandr': data, 'xorg': result})
+
+if __name__ == '__main__':
+    module = AnsibleModule(argument_spec=ARG_SPECS, supports_check_mode=False,)
+    try:
+        d = subprocess.check_output(['xrandr', '-d', module.params['display'], '--verbose'], universal_newlines=True).splitlines()
+    except subprocess.CalledProcessError:
+        xorg_data = {}
+    else:
+        xorg_data = parse_xrandr_verbose(iter(d))
+    output_data(xorg_data, module.params['write_edids'])
+
+
+
+
+
+
+

9 Handlers

+
+
+
- name: Reconfigure unattended upgrades with dpkg
+  command: '/usr/sbin/dpkg-reconfigure --frontend noninteractive unattended-upgrades'
+
+- name: Trigger Udev
+  command: 'udevadm trigger '
+  
+- name: Restart Samba
+  systemd:
+    name: smbd.service
+    state: restarted
+    enabled: yes
+    #masked: no
+  register: samba_reload
+
+- name: Restart NFS Kernel Server
+  systemd:
+    name: nfs-server.service
+    state: restarted
+    enabled: yes
+    #masked: no
+  register: nfs_reload
+
+- name: Restart VDR
+  systemd:
+    name: vdr.service
+    state: restarted
+    enabled: yes
+  register: vdr_restart
+
+- name: Stop VDR
+  systemd:
+    name: vdr.service
+    state: stopped
+    enabled: yes
+  register: vdr_stop
+
+- name: Start VDR
+  systemd:
+    name: vdr.service
+    state: started
+    enabled: yes
+  register: vdr_start
+
+- name: Stop xlogin
+  systemd:
+    name: xlogin@vdr.service
+    state: stopped
+    enabled: yes
+  register: xlogin_stop
+
+- name: Start xlogin
+  systemd:
+    daemon_reload: yes
+    name: 'xlogin@{{ vdr.user }}'
+    enabled: yes
+    state: started
+  register: xlogin_start
+
+- name: Stop x
+  systemd:
+    name: x@vt7.service
+    state: stopped
+  register: x_stop
+
+
+
+

Autor: Alexander Grothe <seahawk1986@gmx.de>

-

Created: 2018-01-16 Di 14:56

+

Created: 2018-01-16 Di 14:58

Validate

diff --git a/Manual.org b/Manual.org index 04ae960..7385972 100644 --- a/Manual.org +++ b/Manual.org @@ -1904,9 +1904,9 @@ xorg_data: {} - name: save results block: - name: write xorg and xrandr variable to xorg_data dictionary - set_fact: + - set_fact: xorg_data: '{{ xorg_data|combine({item[0]: item[1]}) }}' - with_items: + with_items: - ('xorg', xorg) - ('xrandr', xrandr['Screen 0:']) diff --git a/roles/yavdr-xorg/tasks/detect-xorg.yml b/roles/yavdr-xorg/tasks/detect-xorg.yml index 58655ca..0b34881 100644 --- a/roles/yavdr-xorg/tasks/detect-xorg.yml +++ b/roles/yavdr-xorg/tasks/detect-xorg.yml @@ -102,9 +102,9 @@ - name: save results block: - name: write xorg and xrandr variable to xorg_data dictionary - set_fact: + - set_fact: xorg_data: '{{ xorg_data|combine({item[0]: item[1]}) }}' - with_items: + with_items: - ('xorg', xorg) - ('xrandr', xrandr['Screen 0:'])