"""Support for discovery using GDM (Good Day Mate), multicast protocol by Plex.

Inspired by
  hippojay's plexGDM:
  https://github.com/hippojay/script.plexbmc.helper/resources/lib/plexgdm.py
  iBaa's PlexConnect: https://github.com/iBaa/PlexConnect/PlexAPI.py
"""
import threading
import socket


class GDM(object):
    """Base class to discover GDM services."""

    def __init__(self):
        self.entries = []
        self.last_scan = None
        self._lock = threading.RLock()

    def scan(self):
        ''' Scan the network. '''
        with self._lock:
            self.update()

    def all(self):
        """
        Returns all found entries.
        Will scan for entries if not scanned recently.
        """
        self.scan()
        return list(self.entries)

    def find_by_content_type(self, value):
        '''
        Return a list of entries that match the content_type
        '''
        self.scan()
        return [entry for entry in self.entries
                if value in entry['data']['Content_Type']]

    def find_by_data(self, values):
        '''
        Return a list of entries that match the search parameters
        '''
        self.scan()
        return [entry for entry in self.entries
                if all(item in entry['data'].items()
                       for item in values.items())]

    def update(self):
        '''
        Scans for new GDM services.

        Example of the dict list returned by this function:
        [{'data': 'Content-Type: plex/media-server'
                  'Host: 53f4b5b6023d41182fe88a99b0e714ba.plex.direct'
                  'Name: myfirstplexserver'
                  'Port: 32400'
                  'Resource-Identifier: 646ab0aa8a01c543e94ba975f6fd6efadc36b7'
                  'Updated-At: 1444852697'
                  'Version: 0.9.12.13.1464-4ccd2ca'
          'from': ('10.10.10.100', 32414)}]
        '''

        gdm_ip = '239.0.0.250'  # multicast to PMS
        gdm_port = 32414
        gdm_msg = 'M-SEARCH * HTTP/1.0'.encode('ascii')
        gdm_timeout = 1

        self.entries = []

        # setup socket for discovery -> multicast message
        sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        sock.settimeout(gdm_timeout)

        # Set the time-to-live for messages for local network
        sock.setsockopt(socket.IPPROTO_IP,
                        socket.IP_MULTICAST_TTL,
                        gdm_timeout)

        try:
            # Send data to the multicast group
            sock.sendto(gdm_msg, (gdm_ip, gdm_port))

            # Look for responses from all recipients
            while True:
                try:
                    data, server = sock.recvfrom(1024)
                    data = data.decode('ascii')
                    if '200 OK' in data.splitlines()[0]:
                        data = {k: v.strip() for (k, v) in (
                            line.split(':') for line in
                            data.splitlines() if ':' in line)}
                        self.entries.append({'data': data,
                                             'from': server})
                except socket.timeout:
                    break
        finally:
            sock.close()


def main():
    """Test GDM discovery."""
    # pylint: disable=invalid-name
    from pprint import pprint

    gdm = GDM()

    pprint("Scanning GDM..")
    gdm.update()
    pprint(gdm.entries)

if __name__ == "__main__":
    main()

@@ -1,11 +1,12 @@
 %22%22%22
+%0A
 Support 
@@ -511,12 +511,11 @@
     
-''' 
+%22%22%22
 Scan
@@ -527,20 +527,19 @@
 network.
- '''
+%22%22%22
 %0A       
@@ -617,24 +617,14 @@
  %22%22%22
-%0A        
 Return
-s
  all
@@ -639,16 +639,17 @@
 ntries.%0A
+%0A
         
@@ -809,36 +809,27 @@
 e):%0A        
-'''%0A        
+%22%22%22
 Return a lis
@@ -868,28 +868,20 @@
 ent_type
-%0A        '''
+.%22%22%22
 %0A       
@@ -1045,28 +1045,19 @@
         
-'''%0A        
+%22%22%22
 Return a
@@ -1105,28 +1105,20 @@
 rameters
-%0A        '''
+.%22%22%22
 %0A       
@@ -1318,25 +1318,15 @@
     
-'''%0A        
+%22%22%22
 Scan
-s
  for
@@ -1835,11 +1835,11 @@
     
-'''
+%22%22%22
 %0A%0A  
@@ -2675,29 +2675,29 @@
 ata.decode('
-ascii
+utf-8
 ')%0A         
@@ -3275,24 +3275,24 @@
 dm = GDM()%0A%0A
-
     pprint(%22
@@ -3305,16 +3305,17 @@
 ng GDM..
+.
 %22)%0A    g

Switch to utf-8 for data (fixes #32) (#36)