mirror of
https://github.com/CCOSTAN/Home-AssistantConfig.git
synced 2025-08-18 11:16:37 +00:00
111 lines
3.3 KiB
Python
111 lines
3.3 KiB
Python
"""
|
|
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):
|
|
"""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 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('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."""
|
|
# pylint: disable=invalid-name
|
|
from pprint import pprint
|
|
|
|
gdm = GDM()
|
|
|
|
pprint("Scanning GDM...")
|
|
gdm.update()
|
|
pprint(gdm.entries)
|
|
|
|
if __name__ == "__main__":
|
|
main()
|