<commit_before># -*- coding: utf-8 -*-
# pylint: disable=C0302
""" The core module contains SonosDiscovery and SoCo classes that implement
the main entry to the SoCo functionality
"""

from __future__ import unicode_literals

try:
    import xml.etree.cElementTree as XML
except ImportError:
    import xml.etree.ElementTree as XML

import select
import socket
import logging
import traceback
import re

import requests

from .services import DeviceProperties, ContentDirectory
from .services import RenderingControl, AVTransport

from .utils import really_unicode, really_utf8, camel_to_underscore

LOGGER = logging.getLogger(__name__)


class SonosDiscovery(object):  # pylint: disable=R0903
    """A simple class for discovering Sonos speakers.

    Public functions:
    get_speaker_ips -- Get a list of IPs of all zoneplayers.

    """

    def __init__(self):
        self._sock = socket.socket(
            socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
        self._sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 2)

    def get_speaker_ips(self):
        """ Get a list of ips for Sonos devices that can be controlled """
        speakers = []
        self._sock.sendto(really_utf8(PLAYER_SEARCH), (MCAST_GRP, MCAST_PORT))

        while True:
            response, _, _ = select.select([self._sock], [], [], 1)
            if response:
                data, addr = self._sock.recvfrom(2048)
                # Look for the model in parentheses in a line like this
                # SERVER: Linux UPnP/1.0 Sonos/22.0-65180 (ZPS5)
                search = re.search(br'SERVER.*\((.*)\)', data)
                try:
                    model = really_unicode(search.group(1))
                except AttributeError:
                    model = None

                # BR100 = Sonos Bridge,        ZPS3 = Zone Player 3
                # ZP120 = Zone Player Amp 120, ZPS5 = Zone Player 5
                # ZP90  = Sonos Connect
                # If it's the bridge, then it's not a speaker and shouldn't
                # be returned
                if (model and model != "BR100"):
                    speakers.append(addr[0])
            else:
                break
        return speakers


class SoCo(object):  # pylint: disable=R0904
    """A simple class for controlling a Sonos speaker

    Public functions::
<commit_msg>Added ZPS1 Zone Player 1 in comment.<commit_after># -*- coding: utf-8 -*-
# pylint: disable=C0302
""" The core module contains SonosDiscovery and SoCo classes that implement
the main entry to the SoCo functionality
"""

from __future__ import unicode_literals

try:
    import xml.etree.cElementTree as XML
except ImportError:
    import xml.etree.ElementTree as XML

import select
import socket
import logging
import traceback
import re

import requests

from .services import DeviceProperties, ContentDirectory
from .services import RenderingControl, AVTransport

from .utils import really_unicode, really_utf8, camel_to_underscore

LOGGER = logging.getLogger(__name__)


class SonosDiscovery(object):  # pylint: disable=R0903
    """A simple class for discovering Sonos speakers.

    Public functions:
    get_speaker_ips -- Get a list of IPs of all zoneplayers.

    """

    def __init__(self):
        self._sock = socket.socket(
            socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
        self._sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 2)

    def get_speaker_ips(self):
        """ Get a list of ips for Sonos devices that can be controlled """
        speakers = []
        self._sock.sendto(really_utf8(PLAYER_SEARCH), (MCAST_GRP, MCAST_PORT))

        while True:
            response, _, _ = select.select([self._sock], [], [], 1)
            if response:
                data, addr = self._sock.recvfrom(2048)
                # Look for the model in parentheses in a line like this
                # SERVER: Linux UPnP/1.0 Sonos/22.0-65180 (ZPS5)
                search = re.search(br'SERVER.*\((.*)\)', data)
                try:
                    model = really_unicode(search.group(1))
                except AttributeError:
                    model = None

                # BR100 = Sonos Bridge,        ZPS3 = Zone Player 3
                # ZP120 = Zone Player Amp 120, ZPS5 = Zone Player 5
                # ZP90  = Sonos Connect,       ZPS1 = Zone Player 1
                # If it's the bridge, then it's not a speaker and shouldn't
                # be returned
                if (model and model != "BR100"):
                    speakers.append(addr[0])
            else:
                break
        return speakers


class SoCo(object):  # pylint: disable=R0904
    """A simple class for controlling a Sonos speaker

    Public functions::

{'fraction_non_alphanumeric': 0.08384114309728935, 'fraction_numerical': 0.02269384324437907, 'mean_word_length': 2.218390804597701, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 4}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '449393', 'n_tokens_mistral': 1462, 'n_tokens_neox': 1317, 'n_words': 428}