def channel_metadata(self, channel_number, rewind=0): channel_number = int(channel_number) rewind = int(rewind) if channel_number not in self.sbe.sxm.lineup: return self.file_not_found() channel = self.sbe.sxm.lineup[channel_number] channel_id = str(channel['channelKey']) packet = next(self.sbe.sxm.packet_generator(channel_id, rewind)) metadata = None for pes_packet in mpegutils.parse_transport_stream(packet): if pes_packet['pid'] == 1024: for es_packet in mpegutils.parse_packetized_elementary_stream(pes_packet['payload']): new_meta = mpegutils.parse_sxm_metadata(es_packet['payload']) if not metadata and new_meta: metadata = new_meta response = json.dumps({ 'channel': channel, 'nowplaying': { 'artist': metadata[1], 'title': metadata[0], 'album': metadata[2], }, }, sort_keys=True, indent=4).encode('utf-8') self.send_standard_headers(len(response), { 'Content-type': 'application/json', }) self.wfile.write(response)
def media_segment(channel_number, segment): segment_data = sxm.get_segment(sxm.lineup[channel_number]["channelKey"], segment) audio = bytearray() metadata = bytearray() pcr = None for packet in mpegutils.parse_transport_stream(segment_data): if pcr == None and "pcr_base" in packet: pcr = packet["pcr_base"] if packet["pid"] == 768: audio += packet["payload"] elif packet["pid"] == 1024: metadata += packet["payload"] audio_adts = bytearray() for packet in mpegutils.parse_packetized_elementary_stream(audio): audio_adts += packet["payload"] id3 = mpegutils.create_id3(pcr, "Title", "Artist") return Response(id3 + audio_adts, mimetype="application/octet-stream")
def media_segment(channel_number, segment): segment_data = sxm.get_segment(sxm.lineup[channel_number]['channelKey'], segment) audio = bytearray() metadata = bytearray() pcr = None for packet in mpegutils.parse_transport_stream(segment_data): if pcr == None and 'pcr_base' in packet: pcr = packet['pcr_base'] if packet['pid'] == 768: audio += packet['payload'] elif packet['pid'] == 1024: metadata += packet['payload'] audio_adts = bytearray() for packet in mpegutils.parse_packetized_elementary_stream(audio): audio_adts += packet['payload'] id3 = mpegutils.create_id3(pcr, 'Title', 'Artist') return Response(id3 + audio_adts, mimetype='application/octet-stream')
def channel_metadata(self, channel_number, rewind=0): channel_number = int(channel_number) rewind = int(rewind) if channel_number not in self.sbe.sxm.lineup: return self.file_not_found() channel = self.sbe.sxm.lineup[channel_number] channel_id = str(channel['channelKey']) packet = next(self.sbe.sxm.packet_generator(channel_id, rewind)) metadata = None for pes_packet in mpegutils.parse_transport_stream(packet): if pes_packet['pid'] == 1024: for es_packet in mpegutils.parse_packetized_elementary_stream( pes_packet['payload']): new_meta = mpegutils.parse_sxm_metadata( es_packet['payload']) if not metadata and new_meta: metadata = new_meta response = json.dumps( { 'channel': channel, 'nowplaying': { 'artist': metadata[1], 'title': metadata[0], 'album': metadata[2], }, }, sort_keys=True, indent=4).encode('utf-8') self.send_standard_headers(len(response), { 'Content-type': 'application/json', }) self.wfile.write(response)
channel_number = int(sys.argv[1]) channel_key = sxm.lineup[channel_number]['channelKey'] filename = sxm.lineup[channel_number]['name'] + ' ' + datetime.datetime.now().strftime("%y-%m-%d %H-%M") + '.aac' original_playlist = sxm.get_playlist(sxm.lineup[channel_number]['channelKey']) playlist = [x for x in original_playlist.splitlines() if x.endswith('.ts')] for segment in playlist: print(segment) segment_data = sxm.get_segment(channel_key, segment) audio = bytearray() metadata = bytearray() pcr = None for packet in mpegutils.parse_transport_stream(segment_data): if pcr == None and 'pcr_base' in packet: pcr = packet['pcr_base'] if packet['pid'] == 768: audio += packet['payload'] elif packet['pid'] == 1024: metadata += packet['payload'] audio_adts = bytearray() for packet in mpegutils.parse_packetized_elementary_stream(audio): audio_adts += packet['payload'] with open(filename, 'ab') as f: f.write(audio_adts)
def channel_stream(self, channel_number, rewind=0): channel_number = int(channel_number) rewind = int(rewind) if channel_number not in self.sbe.sxm.lineup: return self.file_not_found() channel = self.sbe.sxm.lineup[channel_number] url = 'http://{}:{}/'.format(self.sbe.config('hostname'), self.sbe.config('port')) logging.info('Streaming: Channel #{} "{}" with rewind {}'.format( channel_number, channel['name'], rewind)) self.protocol_version = 'ICY' # if we don't pretend to be shoutcast, doctors HATE us self.send_response_only(200) self.send_header('Content-type', 'audio/aacp') self.send_header('icy-br', '64') self.send_header('icy-name', channel['name']) self.send_header('icy-genre', channel['genre']) self.send_header('icy-url', url) self.send_header('icy-metaint', '32768') self.end_headers() channel_id = str(channel['channelKey']) track_title = '' start_time = None new_meta = False audio = bytearray() for ts_packet in self.sbe.sxm.packet_generator(channel_id, rewind): pes_streams = collections.defaultdict(bytearray) for pes_packet in mpegutils.parse_transport_stream(ts_packet): if 'payload' in pes_packet: pes_streams[pes_packet['pid']].extend(pes_packet['payload']) for pid, pes_stream in pes_streams.items(): for es_packet in mpegutils.parse_packetized_elementary_stream(pes_stream): if pid == 768: audio.extend(es_packet['payload']) elif pid == 1024: metadata = mpegutils.parse_sxm_metadata(es_packet['payload']) if metadata: new_title = '{} - {}'.format(metadata[1], metadata[0]) if new_title != track_title: logging.info("Now playing: " + new_title) track_title = new_title new_meta = True if len(audio) >= 32768: if new_meta: meta_title = ("StreamTitle='" + track_title.replace("'", '') + "';").encode('utf-8') meta_length = math.ceil(len(meta_title) / 16) meta_buffer = bytes((meta_length,)) + meta_title + (b'\x00' * ((meta_length * 16) - len(meta_title))) new_meta = False logging.debug('Metadata: ' + repr(meta_buffer)) else: meta_buffer = b'\x00' audio_interval = audio[:32768] del audio[:32768] try: self.wfile.write(audio_interval) self.wfile.write(meta_buffer) if start_time != None and time.time() - start_time < 4: time.sleep(4 - (time.time() - start_time)) start_time = time.time() except (ConnectionResetError, ConnectionAbortedError) as e: logging.info('Connection dropped: ' + str(e)) return
channel_number = int(sys.argv[1]) channel_key = sxm.lineup[channel_number]["channelKey"] filename = sxm.lineup[channel_number]["name"] + " " + datetime.datetime.now().strftime("%y-%m-%d %H-%M") + ".aac" original_playlist = sxm.get_playlist(sxm.lineup[channel_number]["channelKey"]) playlist = [x for x in original_playlist.splitlines() if x.endswith(".ts")] for segment in playlist: print(segment) segment_data = sxm.get_segment(channel_key, segment) audio = bytearray() metadata = bytearray() pcr = None for packet in mpegutils.parse_transport_stream(segment_data): if pcr == None and "pcr_base" in packet: pcr = packet["pcr_base"] if packet["pid"] == 768: audio += packet["payload"] elif packet["pid"] == 1024: metadata += packet["payload"] audio_adts = bytearray() for packet in mpegutils.parse_packetized_elementary_stream(audio): audio_adts += packet["payload"] with open(filename, "ab") as f: f.write(audio_adts)
def channel_stream(self, channel_number, rewind=0): channel_number = int(channel_number) rewind = int(rewind) if channel_number not in self.sbe.sxm.lineup: return self.file_not_found() channel = self.sbe.sxm.lineup[channel_number] url = 'http://{}:{}/'.format(self.sbe.config('hostname'), self.sbe.config('port')) logging.info('Streaming: Channel #{} "{}" with rewind {}'.format( channel_number, channel['name'], rewind)) self.protocol_version = 'ICY' # if we don't pretend to be shoutcast, doctors HATE us self.send_response_only(200) self.send_header('Content-type', 'audio/aacp') self.send_header('icy-br', '64') self.send_header('icy-name', channel['name']) self.send_header('icy-genre', channel['genre']) self.send_header('icy-url', url) self.send_header('icy-metaint', '32768') self.end_headers() channel_id = str(channel['channelKey']) track_title = '' start_time = None new_meta = False audio = bytearray() for ts_packet in self.sbe.sxm.packet_generator(channel_id, rewind): pes_streams = collections.defaultdict(bytearray) for pes_packet in mpegutils.parse_transport_stream(ts_packet): if 'payload' in pes_packet: pes_streams[pes_packet['pid']].extend( pes_packet['payload']) for pid, pes_stream in pes_streams.items(): for es_packet in mpegutils.parse_packetized_elementary_stream( pes_stream): if pid == 768: audio.extend(es_packet['payload']) elif pid == 1024: metadata = mpegutils.parse_sxm_metadata( es_packet['payload']) if metadata: new_title = '{} - {}'.format( metadata[1], metadata[0]) if new_title != track_title: logging.info("Now playing: " + new_title) track_title = new_title new_meta = True if len(audio) >= 32768: if new_meta: meta_title = ("StreamTitle='" + track_title.replace("'", '') + "';").encode('utf-8') meta_length = math.ceil(len(meta_title) / 16) meta_buffer = bytes( (meta_length, )) + meta_title + (b'\x00' * ( (meta_length * 16) - len(meta_title))) new_meta = False logging.debug('Metadata: ' + repr(meta_buffer)) else: meta_buffer = b'\x00' audio_interval = audio[:32768] del audio[:32768] try: self.wfile.write(audio_interval) self.wfile.write(meta_buffer) if start_time != None and time.time( ) - start_time < 4: time.sleep(4 - (time.time() - start_time)) start_time = time.time() except (ConnectionResetError, ConnectionAbortedError) as e: logging.info('Connection dropped: ' + str(e)) return