Skip to content

Commit e97a39b

Browse files
committed
Add support to scan for Plex clients
1 parent 2af8974 commit e97a39b

File tree

1 file changed

+48
-14
lines changed

1 file changed

+48
-14
lines changed

plexapi/gdm.py

Lines changed: 48 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ def __init__(self):
2121
self.entries = [] # type: List[Dict[str, Any]]
2222
self.last_scan = None
2323

24-
def scan(self):
24+
def scan(self, scan_for_clients=False):
2525
"""Scan the network."""
26-
self.update()
26+
self.update(scan_for_clients)
2727

2828
def all(self):
2929
"""Return all found entries.
@@ -46,28 +46,43 @@ def find_by_data(self, values):
4646
if all(item in entry['data'].items()
4747
for item in values.items())]
4848

49-
def update(self):
49+
def update(self, scan_for_clients):
5050
"""Scan for new GDM services.
5151
52-
Example of the dict list assigned to self.entries by this function:
52+
Examples of the dict list assigned to self.entries by this function:
53+
54+
Server:
5355
[{'data': {
5456
'Content-Type': 'plex/media-server',
5557
'Host': '53f4b5b6023d41182fe88a99b0e714ba.plex.direct',
5658
'Name': 'myfirstplexserver',
5759
'Port': '32400',
5860
'Resource-Identifier': '646ab0aa8a01c543e94ba975f6fd6efadc36b7',
59-
'Updated-At': '1444852697',
60-
'Version': '0.9.12.13.1464-4ccd2ca',
61-
},
62-
'from': ('10.10.10.100', 32414)}]
61+
'Updated-At': '1585769946',
62+
'Version': '1.18.8.2527-740d4c206',
63+
},
64+
'from': ('10.10.10.100', 32414)}]
65+
66+
Clients:
67+
[{'data': {'Content-Type': 'plex/media-player',
68+
'Device-Class': 'stb',
69+
'Name': 'plexamp',
70+
'Port': '36000',
71+
'Product': 'Plexamp',
72+
'Protocol': 'plex',
73+
'Protocol-Capabilities': 'timeline,playback,playqueues,playqueues-creation',
74+
'Protocol-Version': '1',
75+
'Resource-Identifier': 'b6e57a3f-e0f8-494f-8884-f4b58501467e',
76+
'Version': '1.1.0',
77+
},
78+
'from': ('10.10.10.101', 32412)}]
6379
"""
6480

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

7084
self.entries = []
85+
known_responses = []
7186

7287
# setup socket for discovery -> multicast message
7388
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
@@ -78,21 +93,36 @@ def update(self):
7893
socket.IP_MULTICAST_TTL,
7994
struct.pack("B", gdm_timeout))
8095

96+
if scan_for_clients:
97+
# setup socket for broadcast to Plex clients
98+
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
99+
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
100+
gdm_ip = '255.255.255.255'
101+
gdm_port = 32412
102+
else:
103+
# setup socket for multicast to Plex server(s)
104+
gdm_ip = '239.0.0.250'
105+
gdm_port = 32414
106+
81107
try:
82108
# Send data to the multicast group
83109
sock.sendto(gdm_msg, (gdm_ip, gdm_port))
84110

85111
# Look for responses from all recipients
86112
while True:
87113
try:
88-
bdata, server = sock.recvfrom(1024)
114+
bdata, host = sock.recvfrom(1024)
89115
data = bdata.decode('utf-8')
90116
if '200 OK' in data.splitlines()[0]:
91117
ddata = {k: v.strip() for (k, v) in (
92118
line.split(':') for line in
93119
data.splitlines() if ':' in line)}
120+
identifier = ddata.get('Resource-Identifier')
121+
if identifier and identifier in known_responses:
122+
continue
123+
known_responses.append(identifier)
94124
self.entries.append({'data': ddata,
95-
'from': server})
125+
'from': host})
96126
except socket.timeout:
97127
break
98128
finally:
@@ -105,8 +135,12 @@ def main():
105135

106136
gdm = GDM()
107137

108-
pprint("Scanning GDM...")
109-
gdm.update()
138+
pprint("Scanning GDM for servers...")
139+
gdm.scan()
140+
pprint(gdm.entries)
141+
142+
pprint("Scanning GDM for clients...")
143+
gdm.scan(scan_for_clients=True)
110144
pprint(gdm.entries)
111145

112146

0 commit comments

Comments
 (0)