|
|
- """
- 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 socket
- import struct
-
-
- class GDM:
- """Base class to discover GDM services."""
-
- def __init__(self):
- self.entries = []
- self.last_scan = None
-
- def scan(self):
- """Scan the network."""
- self.update()
-
- def all(self):
- """Return 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):
- """Scan for new GDM services.
-
- Example of the dict list assigned to self.entries 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,
- struct.pack("B", 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('utf-8')
- 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."""
- from pprint import pprint
-
- gdm = GDM()
-
- pprint("Scanning GDM...")
- gdm.update()
- pprint(gdm.entries)
-
-
- if __name__ == "__main__":
- main()
|