From 5a2f8eed5d09a96bc1e883b44b961184d5538054 Mon Sep 17 00:00:00 2001 From: kokarare1212 Date: Wed, 19 May 2021 20:34:24 +0900 Subject: [PATCH] [Incomplete] Zeroconf feature --- librespot/ZeroconfServer.py | 3 ++ librespot/api/__init__.py | 0 librespot/player/Player.py | 4 +-- librespot/zeroconf/Packet.py | 59 +++++++++++++++++++++++++++++++ librespot/zeroconf/Record.py | 38 ++++++++++++++++++++ librespot/zeroconf/Service.py | 60 +++++++++++++++++++++++++++++++ librespot/zeroconf/Zeroconf.py | 64 ++++++++++++++++++++++++++++++++++ librespot/zeroconf/__init__.py | 1 + requirements.txt | 2 +- 9 files changed, 228 insertions(+), 3 deletions(-) create mode 100644 librespot/api/__init__.py create mode 100644 librespot/zeroconf/Packet.py create mode 100644 librespot/zeroconf/Record.py create mode 100644 librespot/zeroconf/Service.py create mode 100644 librespot/zeroconf/Zeroconf.py create mode 100644 librespot/zeroconf/__init__.py diff --git a/librespot/ZeroconfServer.py b/librespot/ZeroconfServer.py index bb2c6f4..a558d15 100644 --- a/librespot/ZeroconfServer.py +++ b/librespot/ZeroconfServer.py @@ -4,6 +4,8 @@ import concurrent.futures import random import socket +from zeroconf import ServiceBrowser, ServiceInfo, Zeroconf + from librespot.common import Utils from librespot.core import Session from librespot.crypto import DiffieHellman @@ -13,6 +15,7 @@ from librespot.standard import Runnable class ZeroconfServer(Closeable): + SERVICE = "spotify-connect" __MAX_PORT = 65536 __MIN_PORT = 1024 __EOL = "\r\n" diff --git a/librespot/api/__init__.py b/librespot/api/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/librespot/player/Player.py b/librespot/player/Player.py index 043c5ab..3bb6279 100644 --- a/librespot/player/Player.py +++ b/librespot/player/Player.py @@ -35,9 +35,9 @@ class Player(Closeable, PlayerSession.Listener, AudioSink.Listener): self._events = Player.EventsDispatcher(conf) self._sink = AudioSink(conf, self) - self._init_state() + self.__init_state() - def _init_state(self): + def __init_state(self): self._state = StateWrapper.StateWrapper(self._session, self, self._conf) diff --git a/librespot/zeroconf/Packet.py b/librespot/zeroconf/Packet.py new file mode 100644 index 0000000..7bfce34 --- /dev/null +++ b/librespot/zeroconf/Packet.py @@ -0,0 +1,59 @@ +import struct + + +class Packet: + __FLAG_RESPONSE: int = 15 + __FLAG_AA: int = 10 + __questions: list + __answers: list + __authorities: list + __additionals: list + __id: int + __flags: int + __address: str + + def __init__(self, _id: int): + self.__id = _id + self.__questions = [] + self.__answers = [] + self.__authorities = [] + self.__additionals = [] + + def get_address(self) -> str: + return self.__address + + def set_address(self, address: str) -> None: + self.__address = address + + def get_id(self) -> int: + return self.__id + + def is_response(self) -> bool: + return self.__is_flag(self.__FLAG_RESPONSE) + + def set_response(self, on: bool) -> None: + self.__set_flag(self.__FLAG_RESPONSE, on) + + def is_authoritative(self) -> bool: + return self.__is_flag(self.__FLAG_AA) + + def set_authoritative(self, on: bool) -> None: + self.__set_flag(self.__FLAG_AA, on) + + def __is_flag(self, flag: int): + return (self.__flags & (1 << flag)) != 0 + + def __set_flag(self, flag: int, on: bool): + if on: + self.__flags |= (1 << flag) + else: + self.__flags &= ~(1 << flag) + + def read(self, inp: bytes, address: str): + self.__address = address + self.__id = struct.unpack(" Service: + if protocol == "tcp" or protocol == "udp": + self.__protocol = protocol + else: + raise TypeError() + return self + + def get_domain(self) -> str: + return self.__domain + + def set_domain(self, domain: str) -> Service: + if domain is None or len(domain) < 2 or domain[0] != ".": + raise TypeError(domain) + self.__domain = domain + return self + + def get_host(self) -> str: + return self.__host + + def set_host(self, host: str) -> Service: + self.__host = host + return self + + def get_packet(self) -> Packet: + packet = Packet() + return packet diff --git a/librespot/zeroconf/Zeroconf.py b/librespot/zeroconf/Zeroconf.py new file mode 100644 index 0000000..bb88f44 --- /dev/null +++ b/librespot/zeroconf/Zeroconf.py @@ -0,0 +1,64 @@ +from __future__ import annotations +from librespot.standard import Closeable +import base64 +import random +import socket + + +class Zeroconf(Closeable): + __DISCOVERY = "_services._dns-sd._udp.local" + __BROADCAST4: socket.socket + __BROADCAST6: socket.socket + __use_ipv4: bool = True + __use_ipv6: bool = True + __hostname: str + __domain: str + + def __init__(self): + try: + self.__BROADCAST4 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + self.__BROADCAST4.connect(("224.0.0.251", 5353)) + self.__BROADCAST6 = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) + self.__BROADCAST6.connect(("FF02::FB", 5353)) + except Exception as e: + pass + self.set_domain(".local") + self.set_local_host_name(Zeroconf.get_or_create_local_host_name()) + + @staticmethod + def get_or_create_local_host_name() -> str: + host = socket.gethostname() + if host == "localhost": + host = base64.b64encode(random.randint(-9223372036854775808, 9223372036854775807)).decode() + ".local" + return host + + def set_use_ipv4(self, ipv4: bool) -> Zeroconf: + self.__use_ipv4 = ipv4 + return self + + def set_use_ipv6(self, ipv6: bool) -> Zeroconf: + self.__use_ipv6 = ipv6 + return self + + def close(self) -> None: + super().close() + + def get_domain(self) -> str: + return self.__domain + + def set_domain(self, domain: str) -> Zeroconf: + self.__domain = domain + return self + + def get_local_host_name(self) -> str: + return self.__hostname + + def set_local_host_name(self, name: str) -> Zeroconf: + self.__hostname = name + return self + + def handle_packet(self, packet): + pass + + def announce(self, service): + pass diff --git a/librespot/zeroconf/__init__.py b/librespot/zeroconf/__init__.py new file mode 100644 index 0000000..7239a5d --- /dev/null +++ b/librespot/zeroconf/__init__.py @@ -0,0 +1 @@ +from librespot.zeroconf.Packet import Packet diff --git a/requirements.txt b/requirements.txt index 9df540d..8886989 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ defusedxml==0.7.1 protobuf==3.15.8 pycryptodome==3.10.1 -requests==2.25.1 +requests==2.25.1 \ No newline at end of file