8 from media.item import BaseItem
9 from media.item import item_builders, item_loaders, item_id_generators
12 log = logging.getLogger("bot")
15 def get_radio_server_description(url):
18 log.debug("radio: fetching radio server description")
19 p = re.compile('(https?://[^/]*)', re.IGNORECASE)
20 res = re.search(p, url)
21 base_url = res.group(1)
22 url_icecast = base_url + '/status-json.xsl'
23 url_shoutcast = base_url + '/stats?json=1'
25 r = requests.get(url_shoutcast, timeout=10)
27 title_server = data['servertitle']
29 # logging.info("TITLE FOUND SHOUTCAST: " + title_server)
30 except (requests.exceptions.ConnectionError,
31 requests.exceptions.HTTPError,
32 requests.exceptions.ReadTimeout,
33 requests.exceptions.Timeout):
34 error_traceback = traceback.format_exc()
35 error = error_traceback.rstrip().split("\n")[-1]
36 log.debug("radio: unsuccessful attempts on fetching radio description (shoutcast): " + error)
41 r = requests.get(url_icecast, timeout=10)
43 source = data['icestats']['source']
44 if type(source) is list:
46 title_server = source['server_name']
47 if 'server_description' in source:
48 title_server += ' - ' + source['server_description']
49 # logging.info("TITLE FOUND ICECAST: " + title_server)
51 except (requests.exceptions.ConnectionError,
52 requests.exceptions.HTTPError,
53 requests.exceptions.ReadTimeout,
54 requests.exceptions.Timeout):
55 error_traceback = traceback.format_exc()
56 error = error_traceback.rstrip().split("\n")[-1]
57 log.debug("radio: unsuccessful attempts on fetching radio description (icecast): " + error)
62 def get_radio_title(url):
65 log.debug("radio: fetching radio server description")
67 r = requests.get(url, headers={'Icy-MetaData': '1'}, stream=True, timeout=10)
68 icy_metaint_header = int(r.headers['icy-metaint'])
69 r.raw.read(icy_metaint_header)
71 metadata_length = struct.unpack('B', r.raw.read(1))[0] * 16 # length byte
72 metadata = r.raw.read(metadata_length).rstrip(b'\0')
73 logging.info(metadata)
74 # extract title from the metadata
75 m = re.search(br"StreamTitle='([^']*)';", metadata)
80 except (requests.exceptions.ConnectionError,
81 requests.exceptions.HTTPError,
82 requests.exceptions.ReadTimeout,
83 requests.exceptions.Timeout,
85 log.debug("radio: unsuccessful attempts on fetching radio title (icy)")
89 def radio_item_builder(bot, **kwargs):
91 return RadioItem(bot, kwargs['url'], kwargs['name'])
93 return RadioItem(bot, kwargs['url'], '')
96 def radio_item_loader(bot, _dict):
97 return RadioItem(bot, "", "", _dict)
100 def radio_item_id_generator(**kwargs):
101 return hashlib.md5(kwargs['url'].encode()).hexdigest()
104 item_builders['radio'] = radio_item_builder
105 item_loaders['radio'] = radio_item_loader
106 item_id_generators['radio'] = radio_item_id_generator
109 class RadioItem(BaseItem):
110 def __init__(self, bot, url, name="", from_dict=None):
111 if from_dict is None:
112 super().__init__(bot)
115 self.title = get_radio_server_description(self.url) # The title of the radio station
118 self.id = hashlib.md5(url.encode()).hexdigest()
120 super().__init__(bot, from_dict)
121 self.url = from_dict['url']
122 self.title = from_dict['title']
127 self.version += 1 # 0 -> 1, notify the wrapper to save me when validate() is visited the first time
137 dict = super().to_dict()
138 dict['url'] = self.url
139 dict['title'] = self.title
143 def format_debug_string(self):
144 return "[radio] {name} ({url})".format(
149 def format_song_string(self, user):
150 return constants.strings("radio_item",
152 title=get_radio_title(self.url), # the title of current song
153 name=self.title, # the title of radio station
157 def format_current_playing(self, user):
158 return constants.strings("now_playing", item=self.format_song_string(user))
160 def format_short_string(self):
161 return self.title if self.title else self.url
163 def display_type(self):
164 return constants.strings("radio")