Source code for hanyuu.listener

# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from __future__ import print_function
from __future__ import absolute_import

from .. import logger
from .. import config
logger = logger.getChild(__name__)

from asynchat import async_chat
from threading import Thread
import asyncore
import socket


[docs]def start(): global listener, thread listener = Listener() def wrapper(): logger.info("THREADING: Started listener") asyncore.loop() logger.info("THREADING: Stopped listener") thread = Thread(target=wrapper) thread.name = "Listener" thread.daemon = 1 thread.start() return listener
[docs]def shutdown(): try: listener.close() except (NameError): pass
[docs]class Listener(async_chat): READING_DATA = 0 READING_META = 1 READING_METASIZE = 2 READING_HEADERS = 3 def __init__(self): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((config.icecast_host, config.icecast_port)) async_chat.__init__(self, sock=sock) self.ibuffer = [] self.obuffer = 'GET {mount} HTTP/1.1\r\nHOST: {host}\r\nUser-Agent: Hanyuu-sama\r\nIcy-MetaData: 1\r\n\r\n'.format(mount=config.icecast_mount, host=config.icecast_host) self.push(self.obuffer) self.set_terminator('\r\n\r\n') self.status = self.READING_HEADERS self.active = True
[docs] def shutdown(self): self.close_when_done() thread.join() return None
[docs] def collect_incoming_data(self, data): self.ibuffer.append(data)
[docs] def handle_close(self): self.active = False self.close() # don't forget to close the original
[docs] def parse_headers(self, headers): self.headers = {} headers = headers.split('\r\n') self.headers["status"] = tuple(headers[0].split(" ")) for header in headers[1:]: if (not header): break splitted = header.split(":") self.headers[splitted[0].strip()] = splitted[1].strip()
[docs] def found_terminator(self): if (self.status == self.READING_DATA): # We read the current chunk of data # Flush our data, we don't need it right now self.ibuffer = [] # Terminator to 1 to read the size of metadata incoming self.set_terminator(1) self.status = self.READING_METASIZE elif (self.status == self.READING_HEADERS): logging.debug("Reading headers") self.reading_headers = False self.parse_headers("".join(self.ibuffer)) self.ibuffer = [] # Get the meta int value try: self.metaint = int(self.headers["icy-metaint"]) except (KeyError): # Incorrect header, kill ourself after a small timeout self.handle_close() # set terminator to that int self.set_terminator(self.metaint) # Icecast always sends data after the headers, so go to that mode self.status = self.READING_DATA elif (self.status == self.READING_METASIZE): # Do an ord() and then times 16 to get the meta length in bytes self.metalen = ord(self.ibuffer[0]) * 16 # Flush the byte afte reading it self.ibuffer = [] if (self.metalen == 0): self.set_terminator(self.metaint) self.status = self.READING_DATA else: self.set_terminator(self.metalen) self.status = self.READING_META elif (self.status == self.READING_META): # finally reading some metadata incoming_string = "".join(self.ibuffer) incoming_string = incoming_string.rstrip("\x00") metadata = "" for part in incoming_string.split("';"): try: if (part.strip().split("='")[0].lower() == "streamtitle"): metadata = "='".join(part.split("='")[1:]) except (IndexError): pass if (metadata == "fallback"): self.handle_close() return if (metadata != ""): new_song = manager.Song(meta=metadata) np = manager.NP() if (np != new_song): np.change(new_song) # flush buffer self.ibuffer = [] # Change to metaint again for reading data self.set_terminator(self.metaint) # go back to reading data self.status = self.READING_DATA

Project Versions

This Page