diff --git a/Manual.html b/Manual.html index 81c422c..22cd0aa 100644 --- a/Manual.html +++ b/Manual.html @@ -3,7 +3,7 @@ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> - + @@ -238,160 +238,166 @@ for the JavaScript code in this tag.

Inhaltsverzeichnis

-
-

1 Installing and configuring yaVDR with Ansible

+
+

1 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. @@ -413,8 +419,8 @@ sudo ./install-yavdr.sh

-
-

1.1 Install script for local usage

+
+

1.1 Install script for local usage

if (( $EUID != 0 )); then
@@ -437,11 +443,11 @@ ansible-playbook yavdr07.yml -b -i 'localhost_inve
 
-
-

2 Playbooks

+
+

2 Playbooks

-
-

2.1 yavdr07.yml

+
+

2.1 yavdr07.yml

The yavdr07.yml playbook sets up a fully-featured yaVDR installation: @@ -476,8 +482,8 @@ The yavdr07.yml playbook sets up a fully-featured yaVDR installatio

-
-

2.2 yavdr07-headless.yml

+
+

2.2 yavdr07-headless.yml

For a headless server installation yavdr07-headless.yml is a good choice @@ -506,30 +512,25 @@ For a headless server installation yavdr07-headless.yml is a good c

-
-

3 Hosts

+
+

3 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:

-
[yavdr-full]
+
[localhost]
 localhost connection=local
-#192.168.1.116
-
-[yavdr-headless]
-
-[yavdr-client]
 
-
-

4 Group Variables

+
+

4 Group Variables

-
-

4.1 default text for templates

+
+

4.1 default text for templates

# file: group_vars/all
@@ -540,8 +541,8 @@ This playbook can either be used to run the installation on the localhost or any
 
-
-

4.2 PPAs

+
+

4.2 PPAs

branch: unstable
@@ -557,8 +558,8 @@ This playbook can either be used to run the installation on the localhost or any
 
-
-

4.3 VDR user, directories, special configuration and plugins

+
+

4.3 VDR user, directories, special configuration and plugins

# properties of the user vdr and vdr-related options
@@ -583,8 +584,8 @@ This playbook can either be used to run the installation on the localhost or any
 
-
-

4.4 Media directories

+
+

4.4 Media directories

# dictionary of directories for (shared) files. Automatically exported via NFS and Samba if those roles are enabled
@@ -599,8 +600,8 @@ This playbook can either be used to run the installation on the localhost or any
 
-
-

4.5 NFS

+
+

4.5 NFS

nfs:
@@ -609,8 +610,8 @@ This playbook can either be used to run the installation on the localhost or any
 
-
-

4.6 Samba

+
+

4.6 Samba

samba:
@@ -620,8 +621,8 @@ This playbook can either be used to run the installation on the localhost or any
 
-
-

4.7 Additional packages

+
+

4.7 Additional packages

# additional packages you want to install
@@ -634,8 +635,8 @@ This playbook can either be used to run the installation on the localhost or any
 
-
-

4.8 System pre-configuration

+
+

4.8 System pre-configuration

#system:
@@ -648,18 +649,18 @@ This playbook can either be used to run the installation on the localhost or any
 
-
-

5 Roles

+
+

5 Roles

-
-

5.1 yavdr-common

+
+

5.1 yavdr-common

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

-
-

5.1.1 default variables

+
+

5.1.1 default variables

This section is for reference only, please use the files in global_vars for customizations. @@ -671,7 +672,7 @@ This section is for reference only, please use the files in global_vars

-
  1. Repositories
    +
    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.

      @@ -686,7 +687,7 @@ You can set a list of package repositories which provide the necessary packages.
  2. -
  3. Drivers
    +
  4. 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.

    @@ -697,7 +698,7 @@ Automatically installed drivers can be very useful, but if you know you need a c
-
  • Additional Packages
    +
  • Additional Packages

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

    @@ -709,7 +710,7 @@ Add additional packages you would like to have on your installation to this list
  • -
  • VDR
    +
  • VDR

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

    @@ -739,14 +740,14 @@ This section allows you to set the recording directory, the user and group that
  • -
    -

    5.1.2 tasks

    +
    +

    5.1.2 tasks

    yavdr-common executes the following tasks:

    -
    1. main.yml
      1. Disable default installation of recommended packages
        +
        1. main.yml
          1. Disable default installation of recommended packages

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

            @@ -758,7 +759,7 @@ This task prevents apt to automatically install all recommended dependencies for
      2. -
      3. Use bash instead of dash
        +
      4. Use bash instead of dash
        - name: use bash instead of dash
           shell: |
        @@ -768,8 +769,8 @@ This task prevents apt to automatically install all recommended dependencies for
         
      5. -
      6. create user vdr
      7. -
      8. Disable release-upgrade notifications
        +
      9. create user vdr
      10. +
      11. Disable release-upgrade notifications
        - name: disable release-upgrade notifications
           lineinfile:
        @@ -781,7 +782,7 @@ This task prevents apt to automatically install all recommended dependencies for
         
      12. -
      13. Set up package repositories
        +
      14. Set up package repositories
        - name: add yaVDR PPAs
           apt_repository:
        @@ -797,7 +798,7 @@ This task prevents apt to automatically install all recommended dependencies for
         
      15. -
      16. Install essential packages
        +
      17. Install essential packages
        - name: apt | install basic packages
           apt:
        @@ -824,7 +825,7 @@ This task prevents apt to automatically install all recommended dependencies for
         
      18. -
      19. Install additional packages (user defined)
        +
      20. Install additional packages (user defined)
        - name: apt | install extra packages
           apt:
        @@ -836,7 +837,7 @@ This task prevents apt to automatically install all recommended dependencies for
         
      21. -
      22. Gather facts with custom modules
        +
      23. Gather facts with custom modules
        - name: get information about usb and pci hardware and loaded kernel modules
           hardware_facts:
        @@ -859,10 +860,10 @@ This task prevents apt to automatically install all recommended dependencies for
         
      24. -
      25. create media directories
    +
  • create media directories
  • -
    -

    5.1.3 templates

    +
    +

    5.1.3 templates

    {{ ansible_managed_file | comment('c') }}
    @@ -874,13 +875,13 @@ APT::Install-Suggests "0";
     
    -
    -

    5.2 vdr

    +
    +

    5.2 vdr

    -
    -

    5.2.1 tasks

    +
    +

    5.2.1 tasks

    -
    1. install the basic vdr packages
      +
      1. install the basic vdr packages
        ---
         # file: roles/vdr/tasks/main.yml
        @@ -897,7 +898,7 @@ APT::Install-Suggests "0";
         
      2. -
      3. Add svdrp/svdrp-disc to /etc/services
        +
      4. Add svdrp/svdrp-disc to /etc/services
        - name: add svdrp to /etc/services
           lineinfile:
        @@ -913,7 +914,7 @@ APT::Install-Suggests "0";
         
      5. -
      6. Set up the recording directory for the vdr user
        +
      7. Set up the recording directory for the vdr user
        - name: create vdr recdir
           file:
        @@ -947,7 +948,7 @@ APT::Install-Suggests "0";
         
      8. -
      9. Install additional vdr plugins
        +
      10. Install additional vdr plugins

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

        @@ -965,11 +966,11 @@ The additional plugins to install can be set in the variable {{vdr_plugins
    -
    -

    5.3 STARTED yavdr-network

    +
    +

    5.3 STARTED yavdr-network

    -
    -

    5.3.1 default variables

    +
    +

    5.3.1 default variables

    install_avahi: true
    @@ -977,8 +978,8 @@ The additional plugins to install can be set in the variable {{vdr_plugins
     
    -
    -

    5.3.2 tasks

    +
    +

    5.3.2 tasks

    ---
    @@ -1008,11 +1009,11 @@ The additional plugins to install can be set in the variable {{vdr_plugins
     
    -
    -

    5.4 STARTED nfs-server

    +
    +

    5.4 STARTED nfs-server

    -
    -

    5.4.1 tasks

    +
    +

    5.4.1 tasks

    - name: install and configure nfs-kernel-server
    @@ -1029,24 +1030,24 @@ The additional plugins to install can be set in the variable {{vdr_plugins
     
    -
    -

    5.5 TODO yavdr-remote

    +
    +

    5.5 TODO yavdr-remote

    -
    -

    5.5.1 default variables

    +
    +

    5.5.1 default variables

    -
    -

    5.5.2 tasks

    +
    +

    5.5.2 tasks

    -
    -

    5.5.3 templates

    +
    +

    5.5.3 templates

    -
    -

    5.5.4 files

    +
    +

    5.5.4 files

    -
    -

    5.6 TODO automatic X-server configuration

    +
    +

    5.6 TODO automatic X-server configuration

    • [ ] detect connected display
    • @@ -1054,8 +1055,8 @@ The additional plugins to install can be set in the variable {{vdr_plugins
    • [ ] create a xorg.conf for nvidia/intel/amd gpus
    -
    -

    5.6.1 templates

    +
    +

    5.6.1 templates

    # file: roles/yavdr-xorg/templates/vdr-xorg.conf
    @@ -1080,18 +1081,18 @@ systemctl --user import-environment
     
    -
    -

    5.6.2 files

    +
    +

    5.6.2 files

    -
    -

    5.7 yavdr-xorg

    +
    +

    5.7 yavdr-xorg

    -
    -

    5.7.1 default variables

    +
    +

    5.7.1 default variables

    -
    -

    5.7.2 tasks

    +
    +

    5.7.2 tasks

    ---
    @@ -1169,8 +1170,8 @@ systemctl --user import-environment
     
    -
    -

    5.7.3 templates

    +
    +

    5.7.3 templates

    [Unit]
    @@ -1186,13 +1187,34 @@ systemctl --user import-environment
     
    -
    -

    5.8 nfs-server

    +
    +

    5.8 display-data

    -
    -

    5.8.1 tasks

    +
    +

    5.8.1 tasks

    +
    ---
    +# file: roles/display-data/tasks/main.yml
    +
    +- name: "detect xorg configuration"
    +  action: xorg_facts
    +
    +- debug:
    +    var: xorg
    +    verbosity: 1
    +
    +
    +
    +
    +
    +
    +

    5.9 nfs-server

    +
    +
    +

    5.9.1 tasks

    +
    +
    - name: install nfs server packages
       apt:
         name: '{{ item }}'
    @@ -1211,9 +1233,9 @@ systemctl --user import-environment
     
    -
    -

    5.8.2 templates

    -
    +
    +

    5.9.2 templates

    +
    /srv *(rw,fsid=0,sync,no_subtree_check,all_squash,anongid={{ vdr.gid }},anonuid={{ vdr.uid }})
     {% for name, path in media_dirs.iteritems() %}
    @@ -1224,15 +1246,15 @@ systemctl --user import-environment
     
    -
    -

    5.9 nfs-config

    +
    +

    5.10 nfs-config

    -
    -

    5.10 samba-install

    -
    -
    -

    5.10.1 tasks

    -
    +
    +

    5.11 samba-install

    +
    +
    +

    5.11.1 tasks

    +
    # file: roles/samba-install/tasks/main.yml
     
    @@ -1251,12 +1273,12 @@ systemctl --user import-environment
     
    -
    -

    5.11 samba-config

    -
    -
    -

    5.11.1 tasks

    -
    +
    +

    5.12 samba-config

    +
    +
    +

    5.12.1 tasks

    +
    # file: roles/samba-config/tasks/main.yml
     
    @@ -1279,10 +1301,10 @@ systemctl --user import-environment
     
    -
    -

    5.11.2 templates

    -
    -
    1. smb.conf
      1. global settings
        +
        +

        5.12.2 templates

        +
        +
        1. smb.conf
          1. global settings
            {{ ansible_managed_file | comment }}
             
            @@ -1366,7 +1388,7 @@ systemctl --user import-environment
             
          2. -
          3. media directories
            +
          4. media directories
            {% for name, path in media_dirs.iteritems() %}
             [{{ name }}]
            @@ -1386,7 +1408,7 @@ systemctl --user import-environment
             
          5. -
          6. include custom samba exports
            +
          7. include custom samba exports
            include = /etc/samba/smb.conf.custom
             
            @@ -1394,16 +1416,16 @@ systemctl --user import-environment
        -
        -

        5.12 TODO autoinstall-drivers

        -
        +
        +

        5.13 TODO autoinstall-drivers

        +

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

        -
        -

        5.12.1 sundtek for Sundtek devices (local or network connection)

        -
        +
        +

        5.13.1 sundtek for Sundtek devices (local or network connection)

        +

        Vendor-IDs:

        @@ -1413,15 +1435,15 @@ Vendor-IDs:
        -
        -

        5.12.2 dddvb-dkms if only newer DD cards are detected

        +
        +

        5.13.2 dddvb-dkms if only newer DD cards are detected

        -
        -

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

        +
        +

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

        -
        -

        5.12.4 newly merged DD drivers

        -
        +
        +

        5.13.4 newly merged DD drivers

        +

        from http://www.vdr-portal.de/board18-vdr-hardware/board102-dvb-karten/120817-treiber-der-cine-ctv6-ddbridge-ci-in-den-kernel-integrieren/

        @@ -1429,12 +1451,12 @@ from -

        5.13 autoinstall-satip

        -
        -
        -

        5.13.1 tasks

        -
        +
        +

        5.14 autoinstall-satip

        +
        +
        +

        5.14.1 tasks

        +
        ---
         # file roles/autoinstall-satip/tasks/main.yml
        @@ -1457,12 +1479,12 @@ from 
        -

        5.14 autoinstall-targavfd

        -
        -
        -

        5.14.1 tasks

        -
        +
        +

        5.15 autoinstall-targavfd

        +
        +
        +

        5.15.1 tasks

        +
        ---
         # file roles/autoinstall-targavfd/tasks/main.yml
        @@ -1478,12 +1500,12 @@ from 
        -

        5.15 autoinstall-imonlcd

        -
        -
        -

        5.15.1 tasks

        -
        +
        +

        5.16 autoinstall-imonlcd

        +
        +
        +

        5.16.1 tasks

        +
        ---
         # file roles/autoinstall-imonlcd/tasks/main.yml
        @@ -1500,12 +1522,12 @@ from 
        -

        5.16 autoinstall-libcecdaemon

        -
        -
        -

        5.16.1 tasks

        -
        +
        +

        5.17 autoinstall-libcecdaemon

        +
        +
        +

        5.17.1 tasks

        +
        ---
         # file roles/autoinstall-libcec-daemon/tasks/main.yml
        @@ -1520,12 +1542,12 @@ from 
        -

        5.17 autoinstall-pvr350

        -
        -
        -

        5.17.1 tasks

        -
        +
        +

        5.18 autoinstall-pvr350

        +
        +
        +

        5.18.1 tasks

        +
        ---
         # file roles/autoinstall-pvr350/tasks/main.yml
        @@ -1542,16 +1564,16 @@ from 
        -

        5.18 TODO autoinstall-dvbhddevice

        -
        +
        +

        5.19 TODO autoinstall-dvbhddevice

        +

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

        -
        -

        5.18.1 tasks

        -
        +
        +

        5.19.1 tasks

        +
        ---
         # file roles/autoinstall-dvbhddevice/tasks/main.yml
        @@ -1569,12 +1591,12 @@ Problem: woher kommt der Treiber (AFAIK noch nicht im Kernel)? Die Firmware soll
         
        -
        -

        5.19 autoinstall-dvbsddevice

        -
        -
        -

        5.19.1 tasks

        -
        +
        +

        5.20 autoinstall-dvbsddevice

        +
        +
        +

        5.20.1 tasks

        +
        ---
         # file roles/autoinstall-dvbsddevice/tasks/main.yml
        @@ -1590,9 +1612,9 @@ Problem: woher kommt der Treiber (AFAIK noch nicht im Kernel)? Die Firmware soll
         
        -
        -

        5.20 template-test

        -
        +
        +

        5.21 template-test

        +
        ---
         - name: show vars
        @@ -1819,12 +1841,12 @@ EndSection
         
        -
        -

        5.21 grub-config

        -
        -
        -

        5.21.1 default variables

        -
        +
        +

        5.22 grub-config

        +
        +
        +

        5.22.1 default variables

        +
        system:
           shutdown: poweroff
        @@ -1835,9 +1857,9 @@ EndSection
         
        -
        -

        5.21.2 tasks

        -
        +
        +

        5.22.2 tasks

        +
        - name: custom grub configuration for timeout and reboot halt
           template:
        @@ -1859,9 +1881,9 @@ EndSection
         
        -
        -

        5.21.3 templates

        -
        +
        +

        5.22.3 templates

        +
        #!/bin/sh
         exec tail -n +3 $0
        @@ -1883,9 +1905,9 @@ menuentry "PowerOff" {
         
        -
        -

        5.21.4 handlers

        -
        +
        +

        5.22.4 handlers

        +
        - name: Update GRUB
           command: update-grub
        @@ -1900,15 +1922,15 @@ menuentry "PowerOff" {
         
        -
        -

        6 Modules

        +
        +

        6 Modules

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

        -
        -

        6.1 hardware_facts.py

        +
        +

        6.1 hardware_facts.py

        #!/usr/bin/env python
        @@ -2041,8 +2063,8 @@ This section contains custom modules for the yaVDR Playbooks. They are used to c
         
        -
        -

        6.2 satip_facts.py

        +
        +

        6.2 satip_facts.py

        #!/usr/bin/env python2
        @@ -2112,9 +2134,184 @@ This section contains custom modules for the yaVDR Playbooks. They are used to c
         
        +
        +

        6.3 xorg_facts.py

        +
        +
        +
        #!/usr/bin/env python2
        +
        +DOCUMENTATION = '''
        +---
        +module: xorg_facts
        +short_description: "gather facts about connected monitors and available modelines"
        +description:
        +     - This script needs a running x-server on a given display in order to successfully call xrandr.
        +       The ranking uses the following factors:
        +       1. preferred_refreshrate
        +       2. preferred_resolution
        +       3. preferred_output
        +       For each element a dictionary of values (up to 4 bit [0 .. 256]) may be passed to the module.
        +       The rank is represented by this order of 4-Bit values:
        +       | rrate | resolution | output | internal score
        +       |    50 |  1920x1080 |   HDMI | 0b_0100_0100_0100 = 1092
        +       |    60 |   1280x720 |     DP | 0b_0011_0011_0011 =  819
        +       Returns the connected output, monitors and modelines and a suggestion for the most fitting mode in a dictionary 'xorg'
        +options:
        +    display:
        +        required: False
        +        default: ":0"
        +        description:
        +          - the DISPLAY variable to use when calling xrandr
        +    preferred_outpus:
        +        required: False
        +        default: {"HDMI": 4, "DP": 3, "DVI": 2, "VGA": 1, "TV": 0}
        +        description:
        +          - ranking of the preferred display connectors
        +    preferred_refreshrates:
        +        required: False
        +        default: {"50": 4, "60": 3, "75": 2, "30": 1, "25": 0}
        +        description:
        +          - ranking of the preferred display refreshrate
        +    preferred_resolutions:
        +        required: False
        +        default: {"7680x4320": 8, "3840x2160": 4, "1920x1080": 2, "1280x720": 1, "720x576": 0}
        +        description:
        +           - ranking of the preferred display resolutions
        +'''
        +EXAMPLES = '''
        +- name: "collect facts for connected displays"
        +  action: xserver_facts
        +    display: ":0"
        +
        +- debug:
        +    var: xorg
        +'''
        +
        +import ast
        +import json
        +import re
        +import subprocess
        +import sys
        +import time
        +from collections import OrderedDict, namedtuple
        +
        +from ansible.module_utils.basic import *
        +
        +arg_specs = {
        +    'display': dict(default=[":0", ":0.1"], type='list', required=False),
        +    'multi_display': dict(default=True, type='bool', required=False),
        +    'preferred_outputs': dict(default={"HDMI": 8, "DP": 4, "DVI": 2, "VGA": 1, "TV": 0}, type='dict', required=False),
        +    'preferred_refreshrates': dict(default={50: 8, 60: 4, 75: 3, 30: 2, 25: 1}, type='dict', required=False),
        +    'preferred_resolutions': dict(default={"7680x4320": 8, "3840x2160": 4, "1920x1080": 2, "1280x720": 1, "720x576": 0},
        +                                  type='dict', required=False),
        +    }
        +
        +Mode = namedtuple('Mode', ['score', 'connection', 'resolution', 'refreshrate'])
        +
        +
        +class ModelineTools(object):
        +    def __init__(self, preferred_outputs, preferred_resolutions, preferred_refreshrates):
        +        self.preferred_outputs = preferred_outputs
        +        self.preferred_resolutions = preferred_resolutions
        +        self.preferred_refreshrates = preferred_refreshrates
        +        
        +    def get_score(self, connection, resolution, refreshrate):
        +        connection = connection.split('-')[0]
        +        score = self.preferred_refreshrates.get(int(refreshrate), 0)
        +        score = score << 4
        +        score += self.preferred_resolutions.get(resolution, 0)
        +        #score = score << 4
        +        #score += self.preferred_outputs.get(connection, 0)
        +        return score
        +
        +    @staticmethod
        +    def cleanup_refreshrate(refreshrate):
        +        rrate = refreshrate.replace('+', '').replace('*', '').replace(' ', '').strip()
        +        return int(round(ast.literal_eval(rrate)))
        +    
        +    def sort_mode(self, mode):
        +        x, y = mode.resolution.split('x')
        +        connection = mode.connection.split('-')[0]
        +        return (mode.score, int(x), int(y), self.preferred_outputs.get(connection, 0))
        +    
        +
        +def main():
        +    module = AnsibleModule(argument_spec=arg_specs, supports_check_mode=False,)
        +    display_list = module.params['display']
        +    preferred_outputs = module.params['preferred_outputs']
        +    preferred_resolutions = module.params['preferred_resolutions']
        +    preferred_refreshrates = module.params['preferred_refreshrates']
        +    mtools = ModelineTools(preferred_outputs, preferred_resolutions, preferred_refreshrates)
        +    modes = []
        +    displays = {}
        +    data = {}
        +
        +    for display in display_list:
        +        # call xrandr
        +        try:
        +            xrandr_data = subprocess.check_output(['xrandr', '-q','-d', display],
        +                                                  universal_newlines=True)
        +        except: continue
        +    
        +        for line in xrandr_data.splitlines():
        +            if line.startswith('Screen'):
        +                screen = line.split(':')[0].split()[-1]
        +                screen = "Screen{}".format(screen)
        +                displays[screen] = {}
        +
        +            elif 'connected' in line:
        +                connection = line.split()[0]
        +                displays[screen][connection] = {}
        +                if 'disconnected' in line:
        +                    displays[screen][connection]['connected'] = False
        +                else:
        +                    displays[screen][connection]['connected'] = True
        +                displays[screen][connection]['modes'] = OrderedDict(
        +                    sorted({}.items(), key=lambda t: t.split('_')[0]))
        +
        +            elif line.startswith(' '):
        +                fields = filter(None, re.split(r'\s{2,}', line))
        +                resolution = fields[0]
        +                refreshrates = fields[1:]
        +                r = set()
        +                for refreshrate in refreshrates:
        +                    refreshrate = refreshrate.strip()
        +                    rrate = mtools.cleanup_refreshrate(refreshrate)
        +                    if len(refreshrate) < 2:
        +                        continue
        +                    if '*' in refreshrate:
        +                        current_mode = (resolution, rrate)
        +                        displays[screen][connection]['current_mode'] = current_mode
        +                    if '+' in refreshrate:
        +                        preferred_mode = (resolution, rrate)
        +                        displays[screen][connection]['preferred_mode'] = preferred_mode
        +                    r.add(mtools.cleanup_refreshrate(refreshrate))
        +                    modes.append(Mode(score=mtools.get_score(connection, resolution, rrate), connection=connection,
        +                                 resolution=resolution, refreshrate=rrate))
        +                    displays[screen][connection]['modes'][resolution] = sorted(r)
        +
        +
        +    data['displays'] = displays
        +    data['modes'] = modes
        +    best_mode = max(modes, key=mtools.sort_mode)
        +    data["best_mode"] = {
        +        'connection': best_mode.connection,
        +        'resolution': best_mode.resolution,
        +        'refreshrate': best_mode.refreshrate,
        +    }
        +
        +    module.exit_json(changed=False, ansible_facts={'xorg': data})
        +
        +
        +if __name__ == '__main__':
        +    main()
        +
        -
        -

        7 Handlers

        +
        +
        +
        +
        +

        7 Handlers

        - name: Restart Samba
        @@ -2146,7 +2343,7 @@ This section contains custom modules for the yaVDR Playbooks. They are used to c
         

        Autor: Alexander Grothe

        -

        Created: 2017-03-17 Fr 11:41

        +

        Created: 2017-03-26 So 13:57

        Validate

        diff --git a/Manual.org b/Manual.org index 0545ed2..680a14e 100644 --- a/Manual.org +++ b/Manual.org @@ -97,13 +97,8 @@ For a headless server installation ~yavdr07-headless.yml~ is a good choice 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: #+BEGIN_SRC conf :tangle localhost_inventory :mkdirp yes -[yavdr-full] +[localhost] localhost connection=local -#192.168.1.116 - -[yavdr-headless] - -[yavdr-client] #+END_SRC * Group Variables @@ -615,6 +610,30 @@ systemctl --user import-environment enabled: yes state: started #+END_SRC +*** templates +#+BEGIN_SRC conf :tangle roles/yavdr-xorg/templates/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 +#+END_SRC +** display-data +*** tasks +#+BEGIN_SRC yaml :tangle roles/display-data/tasks/main.yml +--- +# file: roles/display-data/tasks/main.yml + +- name: "detect xorg configuration" + action: xorg_facts + +- debug: + var: xorg + verbosity: 1 +#+END_SRC ** nfs-server *** tasks #+BEGIN_SRC yaml :tangle roles/nfs-server/tasks/main.yml :mkdirp yes @@ -1375,6 +1394,176 @@ def main(): if __name__ == '__main__': main() #+END_SRC +** xorg_facts.py +#+BEGIN_SRC python :tangle library/xorg_facts.py +#!/usr/bin/env python2 + +DOCUMENTATION = ''' +--- +module: xorg_facts +short_description: "gather facts about connected monitors and available modelines" +description: + - This script needs a running x-server on a given display in order to successfully call xrandr. + The ranking uses the following factors: + 1. preferred_refreshrate + 2. preferred_resolution + 3. preferred_output + For each element a dictionary of values (up to 4 bit [0 .. 256]) may be passed to the module. + The rank is represented by this order of 4-Bit values: + | rrate | resolution | output | internal score + | 50 | 1920x1080 | HDMI | 0b_0100_0100_0100 = 1092 + | 60 | 1280x720 | DP | 0b_0011_0011_0011 = 819 + Returns the connected output, monitors and modelines and a suggestion for the most fitting mode in a dictionary 'xorg' +options: + display: + required: False + default: ":0" + description: + - the DISPLAY variable to use when calling xrandr + preferred_outpus: + required: False + default: {"HDMI": 4, "DP": 3, "DVI": 2, "VGA": 1, "TV": 0} + description: + - ranking of the preferred display connectors + preferred_refreshrates: + required: False + default: {"50": 4, "60": 3, "75": 2, "30": 1, "25": 0} + description: + - ranking of the preferred display refreshrate + preferred_resolutions: + required: False + default: {"7680x4320": 8, "3840x2160": 4, "1920x1080": 2, "1280x720": 1, "720x576": 0} + description: + - ranking of the preferred display resolutions +''' +EXAMPLES = ''' +- name: "collect facts for connected displays" + action: xserver_facts + display: ":0" + +- debug: + var: xorg +''' + +import ast +import json +import re +import subprocess +import sys +import time +from collections import OrderedDict, namedtuple + +from ansible.module_utils.basic import * + +arg_specs = { + 'display': dict(default=[":0", ":0.1"], type='list', required=False), + 'multi_display': dict(default=True, type='bool', required=False), + 'preferred_outputs': dict(default={"HDMI": 8, "DP": 4, "DVI": 2, "VGA": 1, "TV": 0}, type='dict', required=False), + 'preferred_refreshrates': dict(default={50: 8, 60: 4, 75: 3, 30: 2, 25: 1}, type='dict', required=False), + 'preferred_resolutions': dict(default={"7680x4320": 8, "3840x2160": 4, "1920x1080": 2, "1280x720": 1, "720x576": 0}, + type='dict', required=False), + } + +Mode = namedtuple('Mode', ['score', 'connection', 'resolution', 'refreshrate']) + + +class ModelineTools(object): + def __init__(self, preferred_outputs, preferred_resolutions, preferred_refreshrates): + self.preferred_outputs = preferred_outputs + self.preferred_resolutions = preferred_resolutions + self.preferred_refreshrates = preferred_refreshrates + + def get_score(self, connection, resolution, refreshrate): + connection = connection.split('-')[0] + score = self.preferred_refreshrates.get(int(refreshrate), 0) + score = score << 4 + score += self.preferred_resolutions.get(resolution, 0) + #score = score << 4 + #score += self.preferred_outputs.get(connection, 0) + return score + + @staticmethod + def cleanup_refreshrate(refreshrate): + rrate = refreshrate.replace('+', '').replace('*', '').replace(' ', '').strip() + return int(round(ast.literal_eval(rrate))) + + def sort_mode(self, mode): + x, y = mode.resolution.split('x') + connection = mode.connection.split('-')[0] + return (mode.score, int(x), int(y), self.preferred_outputs.get(connection, 0)) + + +def main(): + module = AnsibleModule(argument_spec=arg_specs, supports_check_mode=False,) + display_list = module.params['display'] + preferred_outputs = module.params['preferred_outputs'] + preferred_resolutions = module.params['preferred_resolutions'] + preferred_refreshrates = module.params['preferred_refreshrates'] + mtools = ModelineTools(preferred_outputs, preferred_resolutions, preferred_refreshrates) + modes = [] + displays = {} + data = {} + + for display in display_list: + # call xrandr + try: + xrandr_data = subprocess.check_output(['xrandr', '-q','-d', display], + universal_newlines=True) + except: continue + + for line in xrandr_data.splitlines(): + if line.startswith('Screen'): + screen = line.split(':')[0].split()[-1] + screen = "Screen{}".format(screen) + displays[screen] = {} + + elif 'connected' in line: + connection = line.split()[0] + displays[screen][connection] = {} + if 'disconnected' in line: + displays[screen][connection]['connected'] = False + else: + displays[screen][connection]['connected'] = True + displays[screen][connection]['modes'] = OrderedDict( + sorted({}.items(), key=lambda t: t.split('_')[0])) + + elif line.startswith(' '): + fields = filter(None, re.split(r'\s{2,}', line)) + resolution = fields[0] + refreshrates = fields[1:] + r = set() + for refreshrate in refreshrates: + refreshrate = refreshrate.strip() + rrate = mtools.cleanup_refreshrate(refreshrate) + if len(refreshrate) < 2: + continue + if '*' in refreshrate: + current_mode = (resolution, rrate) + displays[screen][connection]['current_mode'] = current_mode + if '+' in refreshrate: + preferred_mode = (resolution, rrate) + displays[screen][connection]['preferred_mode'] = preferred_mode + r.add(mtools.cleanup_refreshrate(refreshrate)) + modes.append(Mode(score=mtools.get_score(connection, resolution, rrate), connection=connection, + resolution=resolution, refreshrate=rrate)) + displays[screen][connection]['modes'][resolution] = sorted(r) + + + data['displays'] = displays + data['modes'] = modes + best_mode = max(modes, key=mtools.sort_mode) + data["best_mode"] = { + 'connection': best_mode.connection, + 'resolution': best_mode.resolution, + 'refreshrate': best_mode.refreshrate, + } + + module.exit_json(changed=False, ansible_facts={'xorg': data}) + + +if __name__ == '__main__': + main() +#+END_SRC * Handlers #+BEGIN_SRC yaml :tangle handlers/main.yml :mkdirp yes - name: Restart Samba diff --git a/displays.yml b/displays.yml new file mode 100644 index 0000000..8887cbf --- /dev/null +++ b/displays.yml @@ -0,0 +1,12 @@ +--- +# file: yavdr07.yml +# this playbook sets up a complete yaVDR 0.7 installation + +- name: set up yaVDR + hosts: all + become: true + roles: + - display-data + + handlers: + - include: handlers/main.yml diff --git a/library/xorg_facts.py b/library/xorg_facts.py new file mode 100644 index 0000000..e10c721 --- /dev/null +++ b/library/xorg_facts.py @@ -0,0 +1,167 @@ +#!/usr/bin/env python2 + +DOCUMENTATION = ''' +--- +module: xorg_facts +short_description: "gather facts about connected monitors and available modelines" +description: + - This script needs a running x-server on a given display in order to successfully call xrandr. + The ranking uses the following factors: + 1. preferred_refreshrate + 2. preferred_resolution + 3. preferred_output + For each element a dictionary of values (up to 4 bit [0 .. 256]) may be passed to the module. + The rank is represented by this order of 4-Bit values: + | rrate | resolution | output | internal score + | 50 | 1920x1080 | HDMI | 0b_0100_0100_0100 = 1092 + | 60 | 1280x720 | DP | 0b_0011_0011_0011 = 819 + Returns the connected output, monitors and modelines and a suggestion for the most fitting mode in a dictionary 'xorg' +options: + display: + required: False + default: ":0" + description: + - the DISPLAY variable to use when calling xrandr + preferred_outpus: + required: False + default: {"HDMI": 4, "DP": 3, "DVI": 2, "VGA": 1, "TV": 0} + description: + - ranking of the preferred display connectors + preferred_refreshrates: + required: False + default: {"50": 4, "60": 3, "75": 2, "30": 1, "25": 0} + description: + - ranking of the preferred display refreshrate + preferred_resolutions: + required: False + default: {"7680x4320": 8, "3840x2160": 4, "1920x1080": 2, "1280x720": 1, "720x576": 0} + description: + - ranking of the preferred display resolutions +''' +EXAMPLES = ''' +- name: "collect facts for connected displays" + action: xserver_facts + display: ":0" + +- debug: + var: xorg +''' + +import ast +import json +import re +import subprocess +import sys +import time +from collections import OrderedDict, namedtuple + +from ansible.module_utils.basic import * + +arg_specs = { + 'display': dict(default=[":0", ":0.1"], type='list', required=False), + 'multi_display': dict(default=True, type='bool', required=False), + 'preferred_outputs': dict(default={"HDMI": 8, "DP": 4, "DVI": 2, "VGA": 1, "TV": 0}, type='dict', required=False), + 'preferred_refreshrates': dict(default={50: 8, 60: 4, 75: 3, 30: 2, 25: 1}, type='dict', required=False), + 'preferred_resolutions': dict(default={"7680x4320": 8, "3840x2160": 4, "1920x1080": 2, "1280x720": 1, "720x576": 0}, + type='dict', required=False), + } + +Mode = namedtuple('Mode', ['score', 'connection', 'resolution', 'refreshrate']) + + +class ModelineTools(object): + def __init__(self, preferred_outputs, preferred_resolutions, preferred_refreshrates): + self.preferred_outputs = preferred_outputs + self.preferred_resolutions = preferred_resolutions + self.preferred_refreshrates = preferred_refreshrates + + def get_score(self, connection, resolution, refreshrate): + connection = connection.split('-')[0] + score = self.preferred_refreshrates.get(int(refreshrate), 0) + score = score << 4 + score += self.preferred_resolutions.get(resolution, 0) + #score = score << 4 + #score += self.preferred_outputs.get(connection, 0) + return score + + @staticmethod + def cleanup_refreshrate(refreshrate): + rrate = refreshrate.replace('+', '').replace('*', '').replace(' ', '').strip() + return int(round(ast.literal_eval(rrate))) + + def sort_mode(self, mode): + x, y = mode.resolution.split('x') + connection = mode.connection.split('-')[0] + return (mode.score, int(x), int(y), self.preferred_outputs.get(connection, 0)) + + +def main(): + module = AnsibleModule(argument_spec=arg_specs, supports_check_mode=False,) + display_list = module.params['display'] + preferred_outputs = module.params['preferred_outputs'] + preferred_resolutions = module.params['preferred_resolutions'] + preferred_refreshrates = module.params['preferred_refreshrates'] + mtools = ModelineTools(preferred_outputs, preferred_resolutions, preferred_refreshrates) + modes = [] + displays = {} + data = {} + + for display in display_list: + # call xrandr + try: + xrandr_data = subprocess.check_output(['xrandr', '-q','-d', display], + universal_newlines=True) + except: continue + + for line in xrandr_data.splitlines(): + if line.startswith('Screen'): + screen = line.split(':')[0].split()[-1] + screen = "Screen{}".format(screen) + displays[screen] = {} + + elif 'connected' in line: + connection = line.split()[0] + displays[screen][connection] = {} + if 'disconnected' in line: + displays[screen][connection]['connected'] = False + else: + displays[screen][connection]['connected'] = True + displays[screen][connection]['modes'] = OrderedDict( + sorted({}.items(), key=lambda t: t.split('_')[0])) + + elif line.startswith(' '): + fields = filter(None, re.split(r'\s{2,}', line)) + resolution = fields[0] + refreshrates = fields[1:] + r = set() + for refreshrate in refreshrates: + refreshrate = refreshrate.strip() + rrate = mtools.cleanup_refreshrate(refreshrate) + if len(refreshrate) < 2: + continue + if '*' in refreshrate: + current_mode = (resolution, rrate) + displays[screen][connection]['current_mode'] = current_mode + if '+' in refreshrate: + preferred_mode = (resolution, rrate) + displays[screen][connection]['preferred_mode'] = preferred_mode + r.add(mtools.cleanup_refreshrate(refreshrate)) + modes.append(Mode(score=mtools.get_score(connection, resolution, rrate), connection=connection, + resolution=resolution, refreshrate=rrate)) + displays[screen][connection]['modes'][resolution] = sorted(r) + + + data['displays'] = displays + data['modes'] = modes + best_mode = max(modes, key=mtools.sort_mode) + data["best_mode"] = { + 'connection': best_mode.connection, + 'resolution': best_mode.resolution, + 'refreshrate': best_mode.refreshrate, + } + + module.exit_json(changed=False, ansible_facts={'xorg': data}) + + +if __name__ == '__main__': + main() diff --git a/localhost_inventory b/localhost_inventory index c286796..a51c139 100644 --- a/localhost_inventory +++ b/localhost_inventory @@ -1,7 +1,2 @@ -[yavdr-full] +[localhost] localhost connection=local -#192.168.1.116 - -[yavdr-headless] - -[yavdr-client] diff --git a/roles/display-data/tasks/main.yml b/roles/display-data/tasks/main.yml new file mode 100644 index 0000000..ae8f802 --- /dev/null +++ b/roles/display-data/tasks/main.yml @@ -0,0 +1,9 @@ +--- +# file: roles/display-data/tasks/main.yml + +- name: "detect xorg configuration" + action: xorg_facts + +- debug: + var: xorg + verbosity: 1 diff --git a/roles/template-test/defaults/main.yml b/roles/template-test/defaults/main.yml new file mode 100644 index 0000000..da426aa --- /dev/null +++ b/roles/template-test/defaults/main.yml @@ -0,0 +1,22 @@ +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" diff --git a/roles/template-test/tasks/main.yml b/roles/template-test/tasks/main.yml new file mode 100644 index 0000000..a2a30b2 --- /dev/null +++ b/roles/template-test/tasks/main.yml @@ -0,0 +1,9 @@ +--- +- name: show vars + debug: + var: '{{ system }}' + +- name: test templates + template: + src: templates/test.j2 + dest: /tmp/test.txt diff --git a/roles/template-test/templates/test.j2 b/roles/template-test/templates/test.j2 new file mode 100644 index 0000000..dd84b0e --- /dev/null +++ b/roles/template-test/templates/test.j2 @@ -0,0 +1,184 @@ +{{ ansible_managed_file | 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 + + +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" ", " + #Option "ConnectedMonitor" + " + + + + + , " +# Option "UseDisplayDevice" "" +# +# +# Option "CustomEDID" ":/etc/X11/edid.0.yavdr" +# +# +# Option "MetaModes" ": { ViewPortIn=x, ViewPortOut=x++ }" +# +# Option "MetaModes" ": { ViewPortIn=x, ViewPortOut=x++ }" +{% 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 + +# +# Option "UseDisplayDevice" "" +# +# +# Option "CustomEDID" ":/etc/X11/edid.1.yavdr" +# +# +# Option "MetaModes" ": { ViewPortIn=x, ViewPortOut=x++ }" +# +# Option "MetaModes" ": { ViewPortIn=x, ViewPortOut=x++ }" +# +EndSection +{% endif %} + +Section "Extensions" +# if no open-gl OSD is needed (e.g. for vdr-sxfe): + Option "Composite" "Disable" +EndSection diff --git a/roles/template-test/vars/main.yml b/roles/template-test/vars/main.yml new file mode 100644 index 0000000..0f734b8 --- /dev/null +++ b/roles/template-test/vars/main.yml @@ -0,0 +1,5 @@ +vars: + foo: + - bar + - baz + - spam diff --git a/roles/yavdr-xorg/templates/x-verbose.service.j2 b/roles/yavdr-xorg/templates/x-verbose.service.j2 new file mode 100644 index 0000000..028dc95 --- /dev/null +++ b/roles/yavdr-xorg/templates/x-verbose.service.j2 @@ -0,0 +1,8 @@ +[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