librespot-python/librespot/ZeroconfServer.py

111 lines
3.2 KiB
Python

from __future__ import annotations
import concurrent.futures
import random
import socket
from zeroconf import ServiceBrowser
from zeroconf import ServiceInfo
from zeroconf import Zeroconf
from librespot.common import Utils
from librespot.core import Session
from librespot.crypto import DiffieHellman
from librespot.proto import Connect_pb2 as Connect
from librespot.standard import Closeable
from librespot.standard import Runnable
class ZeroconfServer(Closeable):
SERVICE = "spotify-connect"
__MAX_PORT = 65536
__MIN_PORT = 1024
__EOL = "\r\n"
__keys: DiffieHellman
__inner: ZeroconfServer.Inner
def __init__(self, inner: ZeroconfServer.Inner, listen_port: int,
listen_all: bool):
self.__inner = inner
self.__keys = DiffieHellman()
if listen_port == -1:
listen_port = random.randint(self.__MIN_PORT, self.__MAX_PORT)
class Builder(Session.AbsBuilder):
__listenAll = False
__listenPort = -1
def __init__(self, conf: Session.Configuration):
super().__init__(conf)
def set_listen_all(self, listen_all: bool) -> ZeroconfServer.Builder:
self.__listenAll = listen_all
return self
def set_listen_port(self, listen_port: int) -> ZeroconfServer.Builder:
self.__listenPort = listen_port
return self
def create(self) -> ZeroconfServer:
return ZeroconfServer(
ZeroconfServer.Inner(
self.device_type,
self.device_name,
self.preferred_locale,
self.conf,
self.device_id,
),
self.__listenPort,
self.__listenAll,
)
class Inner:
device_type: Connect.DeviceType
device_name: str
device_id: str
preferred_locale: str
conf = None
def __init__(
self,
device_type: Connect.DeviceType,
device_name: str,
preferred_locale: str,
conf: Session.Configuration,
device_id: str = None,
):
self.preferred_locale = preferred_locale
self.conf = conf
self.device_type = device_type
self.device_name = device_name
self.device_id = (device_id if device_id is not None else
Utils.random_hex_string(40))
class HttpRunner(Runnable, Closeable):
__sock: socket
__executorService: concurrent.futures.ThreadPoolExecutor = (
concurrent.futures.ThreadPoolExecutor())
__shouldStop: bool = False
def __init__(self, port: int):
self.__sock = socket.socket()
self.__sock.bind(("0.0.0.0", port))
self.__sock.listen(1)
def run(self) -> None:
while not self.__shouldStop:
client, address = self.__sock.accept()
def anonymous():
self.__handle(client)
client.close()
self.__executorService.submit(anonymous)
def __handle(self, client: socket.socket):
client.recv(1)
def close(self) -> None:
super().close()