Skip to content

Commit 24964ce

Browse files
committed
changing station formating for www.radio-browser.info service
1 parent a4a2cd7 commit 24964ce

File tree

2 files changed

+106
-83
lines changed

2 files changed

+106
-83
lines changed

pyradio/browser.py

+96-79
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
1-
#!/usr/bin/env python
21
# -*- coding: utf-8 -*-
32
# http://www.radio-browser.info/webservice#Advanced_station_search
43
import json
54
import requests
6-
import pprint
75
import threading
86
import logging
9-
from .widechar import is_wide, cjklen, PY3
10-
from os import get_terminal_size
7+
from .widechar import cjklen, PY3
8+
#from os import get_terminal_size
119

1210
logger = logging.getLogger(__name__)
1311

12+
1413
class PyRadioStationsBrowser(object):
1514
"""A base class to get results from online radio directory services.
1615
@@ -20,7 +19,7 @@ class PyRadioStationsBrowser(object):
2019
def __init__(self, search=None):
2120
"""Initialize the station's browser.
2221
23-
It should return a valid search result (for example,
22+
It should return a valid search result (for example,
2423
www.radio-browser.info implementation, returns 100 stations
2524
sorted by number of votes).
2625
@@ -31,7 +30,10 @@ def __init__(self, search=None):
3130
"""
3231

3332
self._raw_stations = []
33+
self._last_search = None
3434
self._have_to_retrieve_url = False
35+
self._url_timeout = 3
36+
self._search_timeout = 3
3537

3638
@property
3739
def have_to_retrieve_url(self):
@@ -41,7 +43,7 @@ def have_to_retrieve_url(self):
4143
def have_to_retrieve_url(self, value):
4244
raise ValueError('property is read only')
4345

44-
def stations(self, playlist_format = 1):
46+
def stations(self, playlist_format=1):
4547
return []
4648

4749
def url(self, id_in_list):
@@ -78,6 +80,19 @@ def real_url(self, stationid):
7880

7981
return ''
8082

83+
def set_played(self, id_in_list, played):
84+
"""Note that a player has been played.
85+
86+
Parameters
87+
----------
88+
id_in_list
89+
id in list of stations (0..len-1)
90+
played
91+
True or False
92+
93+
"""
94+
pass
95+
8196
def search(self, data=None):
8297
return []
8398

@@ -106,14 +121,17 @@ class PyRadioBrowserInfoBrowser(PyRadioStationsBrowser):
106121

107122
_have_to_retrieve_url = True
108123

124+
_url_timeout = 3
125+
_search_timeout = 3
126+
109127
def __init__(self, search=None):
110128
self._raw_stations = []
111129
if search:
112130
self.search(search)
113131
else:
114132
self.search({'order': 'votes', 'reverse': 'true'})
115133

116-
def stations(self, playlist_format = 1):
134+
def stations(self, playlist_format=1):
117135
""" Return stations' list (in PyRadio playlist format)
118136
119137
Parameters
@@ -126,7 +144,7 @@ def stations(self, playlist_format = 1):
126144

127145
ret = []
128146
for n in self._raw_stations:
129-
if playlist_format == 0:
147+
if playlist_format == 0:
130148
ret.append([n['name'], n['url']])
131149
elif playlist_format == 1:
132150
enc = '' if n['encoding'] == 'utf-8' else n['encoding']
@@ -163,6 +181,7 @@ def url(self, id_in_list):
163181
logger.debug('URL retrieved: "{0}" <- "{1}'.format(url, self._raw_stations[id_in_list]['url']))
164182
self._raw_stations[id_in_list]['url'] = url
165183
self._raw_stations[id_in_list]['real_url'] = True
184+
self._raw_stations[id_in_list]['played'] = True
166185
else:
167186
if logger.isEnabledFor(logging.ERROR):
168187
logger.error('Failed to retrieve URL for station "{0}", using "{1}"'.format(self._raw_stations[id_in_list]['name'], self._raw_stations[id_in_list]['url']))
@@ -187,7 +206,7 @@ def real_url(self, stationid):
187206
'http://www.radio-browser.info/webservice/v2/json/url/' + \
188207
str(stationid)
189208
try:
190-
r = requests.get(url=url, headers=self._open_headers)
209+
r = requests.get(url=url, headers=self._open_headers, timeout=self._url_timeout)
191210
r.raise_for_status()
192211
rep = json.loads(r.text)
193212
if rep['ok'] == 'true':
@@ -224,6 +243,7 @@ def search(self, data):
224243
votes : station votes
225244
clickcount : station clicks
226245
country : station country
246+
language : station language
227247
encoding : station encoding ('' means utf-8)
228248
"""
229249

@@ -249,9 +269,10 @@ def search(self, data):
249269
post_data['limit'] = 100
250270
if not 'hidebroken' not in post_data.keys():
251271
post_data['hidebroken'] = 'true'
272+
self._last_search = post_data
252273
url = 'http://www.radio-browser.info/webservice/json/stations/search'
253274
try:
254-
r = requests.get(url=url, headers=self._open_headers, json=post_data)
275+
r = requests.get(url=url, headers=self._open_headers, json=post_data, timeout=self._search_timeout)
255276
r.raise_for_status()
256277
self._raw_stations = self._extract_data(json.loads(r.text))
257278
except requests.exceptions.RequestException as e:
@@ -289,67 +310,67 @@ def format_station_line(self, id_in_list, pad, width):
289310
empty string
290311
"""
291312

292-
info = (' [Votes: {0}, Clicks: {1}, Bitrate: {2}kb, Country: {3}]',
293-
' [Votes: {0}, Clicks: {1}, Bitrate: {2}kb]',
294-
' [{0} v, {1} cl, {2}kb]',
295-
' [Bitrate: {}kb]')
296-
now_width = get_terminal_size().columns - 2
313+
info = ('',
314+
' {0} {1}kb',
315+
' {0}{1} v|{2} cl|{3}kb',
316+
' {0} {1}| {2}| {3}kb',
317+
' {0} {1}| {2}| {3}kb|{4}',
318+
' {0} {1}| {2}| {3}kb|{4}|{5}',
319+
)
320+
# now_width = get_terminal_size().columns - 2
297321
now_width = width
298-
if now_width <=45:
299-
self._output_format = 4
300-
elif now_width <=60:
301-
self._output_format = 3
302-
elif now_width <=78:
303-
self._output_format = 2
304-
elif now_width <=105:
322+
if now_width <= 45:
323+
self._output_format = 0
324+
elif now_width <= 55:
305325
self._output_format = 1
326+
elif now_width <= 78:
327+
self._output_format = 2
328+
elif now_width <= 100:
329+
self._output_format = 3
330+
elif now_width <= 125:
331+
self._output_format = 4
306332
else:
307-
self._output_format = 0
308-
309-
#logger.error('DE width = {0}, now_width = {1}'.format(width, now_width))
310-
#if self._output_format == -1:
311-
# self._info_len = []
312-
# self._info_len.append(len(info[0].format(' ' * self._max_len[3],
313-
# ' ' * self._max_len[4],
314-
# ' ' * self._max_len[2],
315-
# ' ' * self._max_len[1])))
316-
# self._info_len.append(len(info[1].format(' ' * self._max_len[3],
317-
# ' ' * self._max_len[4],
318-
# ' ' * self._max_len[2],
319-
# ' ' * self._max_len[1])))
320-
# self._info_len.append(len(info[2].format(' ' * self._max_len[3],
321-
# ' ' * self._max_len[4],
322-
# ' ' * self._max_len[2])))
323-
# self._info_len.append(len(info[3].format(' ' * self._max_len[2])))
324-
# self._info_name_len = len(' ' * pad + '. ' + ' ' * self._max_len[0])
325-
326-
# self._output_format = 4
327-
# if width > 50:
328-
# for i, n in enumerate(self._info_len):
329-
# if n + self._info_name_len < width:
330-
# self._output_format = i
331-
# break
332-
#logger.error('DE output format = {}'.format(self._output_format))
333+
self._output_format = 5
333334

334335
out = ['{0}. '.format(str(id_in_list + 1).rjust(pad)), '', '']
335336

336337
# format info field
337-
if self._output_format == 0:
338+
pl = '-' if self._raw_stations[id_in_list]['played'] else '|'
339+
if self._output_format == 5:
340+
# full with state
341+
out[2] = ' ' + info[self._output_format].format(
342+
pl,
343+
self._raw_stations[id_in_list]['votes'].rjust(self._max_len[0]),
344+
self._raw_stations[id_in_list]['clickcount'].rjust(self._max_len[1]),
345+
self._raw_stations[id_in_list]['bitrate'].rjust(7)[:7],
346+
self._raw_stations[id_in_list]['country'].ljust(14)[:14],
347+
self._raw_stations[id_in_list]['language'].ljust(15)[:15]
348+
)
349+
if self._output_format == 4:
338350
# full or condensed info
339-
out[2] = ' ' + info[self._output_format].format(self._raw_stations[id_in_list]['votes'].rjust(self._max_len[3]),
340-
self._raw_stations[id_in_list]['clickcount'].rjust(self._max_len[4]),
341-
self._raw_stations[id_in_list]['bitrate'].rjust(self._max_len[2]),
342-
self._raw_stations[id_in_list]['country'].ljust(self._max_len[1])[:14])
343-
elif self._output_format in (1, 2):
344-
out[2] = ' ' + info[self._output_format].format(self._raw_stations[id_in_list]['votes'].rjust(self._max_len[3]),
345-
self._raw_stations[id_in_list]['clickcount'].rjust(self._max_len[4]),
346-
self._raw_stations[id_in_list]['bitrate'].rjust(self._max_len[2]))
347-
elif self._output_format == 3:
351+
out[2] = ' ' + info[self._output_format].format(
352+
pl,
353+
self._raw_stations[id_in_list]['votes'].rjust(self._max_len[0]),
354+
self._raw_stations[id_in_list]['clickcount'].rjust(self._max_len[1]),
355+
self._raw_stations[id_in_list]['bitrate'].rjust(7)[:7],
356+
self._raw_stations[id_in_list]['country'].ljust(14)[:14],
357+
)
358+
elif self._output_format in (2, 3):
359+
out[2] = ' ' + info[self._output_format].format(
360+
pl,
361+
self._raw_stations[id_in_list]['votes'].rjust(self._max_len[0]),
362+
self._raw_stations[id_in_list]['clickcount'].rjust(self._max_len[1]),
363+
self._raw_stations[id_in_list]['bitrate'].rjust(7)[:7],
364+
)
365+
elif self._output_format == 1:
348366
# Bitrate only
349-
out[2] = info[self._output_format].format(self._raw_stations[id_in_list]['bitrate'].rjust(self._max_len[2]))
367+
out[2] = info[self._output_format].format(
368+
pl,
369+
self._raw_stations[id_in_list]['bitrate'].rjust(7)[:7]
370+
)
350371

351372
name_width = width-len(out[0])-len(out[2])
352-
out[1] = self._fix_cjk_string_width(self._raw_stations[id_in_list]['name'].ljust(name_width)[:name_width], name_width)
373+
out[1] = self._fix_cjk_string_width(self._raw_stations[id_in_list]['name'].ljust(name_width)[:name_width], name_width)
353374
if PY3:
354375
return '{0}{1}{2}'.format(*out)
355376
else:
@@ -372,27 +393,26 @@ def _fix_cjk_string_width(self, a_string, width):
372393

373394
def _extract_data(self, a_search_result):
374395
ret = []
375-
self._max_len = [0, 0, 0, 0, 0]
396+
self._max_len = [0, 0]
376397
if a_search_result:
377398
for n in a_search_result:
378399
ret.append({'name': n['name'].replace(',', ' ')})
379400
ret[-1]['bitrate'] = n['bitrate']
380401
ret[-1]['votes'] = n['votes']
381402
ret[-1]['url'] = n['url']
382403
ret[-1]['real_url'] = False
404+
ret[-1]['played'] = False
383405
ret[-1]['hls'] = n['hls']
384406
ret[-1]['id'] = n['id']
385407
ret[-1]['country'] = n['country']
408+
ret[-1]['language'] = n['language']
386409
ret[-1]['clickcount'] = n['clickcount']
387410
ret[-1]['encoding'] = ''
388-
self._get_max_len(string_data = (ret[-1]['name'],
389-
ret[-1]['country']),
390-
numeric_data = (ret[-1]['bitrate'],
391-
ret[-1]['votes'],
392-
ret[-1]['clickcount']))
411+
self._get_max_len(ret[-1]['votes'],
412+
ret[-1]['clickcount'])
393413
return ret
394414

395-
def _get_max_len(self, string_data, numeric_data):
415+
def _get_max_len(self, votes, clicks):
396416
""" Calculate the maximum length of numeric_data / country
397417
398418
Parameters
@@ -414,16 +434,11 @@ def _get_max_len(self, string_data, numeric_data):
414434
max clickcount length]
415435
"""
416436

417-
for i, n in enumerate(string_data):
418-
l = cjklen(n)
419-
if l > self._max_len[i]:
420-
self._max_len[i] = l
421-
if self._max_len[0] > 50: self._max_len[0] = 50
422-
if self._max_len[0] > 14: self._max_len[1] = 14
423-
add = len(string_data)
437+
numeric_data = (votes, clicks)
438+
min_data = (6, 7)
424439
for i, n in enumerate(numeric_data):
425-
if len(n) > self._max_len[i+add]:
426-
self._max_len[i+add] = len(n)
440+
if len(n) > self._max_len[i]:
441+
self._max_len[i] = len(n) if len(n) > min_data[i] else min_data[i]
427442

428443

429444
class PyRadioBrowserInfoData(object):
@@ -436,10 +451,11 @@ class PyRadioBrowserInfoData(object):
436451
_connection_error = False
437452
_lock = threading.Lock()
438453
_stop_thread = False
454+
_timeout = 3
439455
data_thread = None
440456

441-
def __init__(self):
442-
pass
457+
def __init__(self, timeout=3):
458+
self._timeout = timeout
443459

444460
def start(self, force_update=False):
445461
""" Start data acquisition thread """
@@ -583,7 +599,7 @@ def get_data_dict(data):
583599
headers = {'user-agent': 'PyRadio/dev',
584600
'encoding': 'application/json'}
585601
try:
586-
r = requests.get(url, headers=headers, json=jdata)
602+
r = requests.get(url, headers=headers, json=jdata, timeout=self._timeout)
587603
r.raise_for_status()
588604
return False, json.loads(r.text)
589605
# if r.status_code == 200:
@@ -613,6 +629,7 @@ def get_data_dict(data):
613629
callback(my_data, ret)
614630
lock.release()
615631

632+
616633
def probeBrowsers(a_browser_url):
617634
base_url = a_browser_url.split('/')[2]
618635
if not base_url:

pyradio/log.py

+10-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# -*- coding: utf-8 -*-
22
from sys import version_info
3+
import logging
4+
5+
logger = logging.getLogger(__name__)
6+
37

48
class Log(object):
59
""" Log class that outputs text to a curses screen """
@@ -29,12 +33,12 @@ def write(self, msg, thread_lock=None, help_msg=False):
2933
self.cursesScreen.erase()
3034
try:
3135
self.msg = msg.strip()
32-
self.cursesScreen.addstr(0, 1, self.msg[0: self.width]
33-
.replace("\r", "").replace("\n", ""))
36+
self.cursesScreen.addstr(0, 1, self.msg[0: self.width].replace("\r", "").replace("\n", ""))
3437
except:
3538
self.msg = msg.encode('utf-8', 'replace').strip()
36-
self.cursesScreen.addstr(0, 1, self.msg[0: self.width]
37-
.replace("\r", "").replace("\n", ""))
39+
self.cursesScreen.addstr(0, 1, self.msg[0: self.width].replace("\r", "").replace("\n", ""))
40+
if logger.isEnabledFor(logging.DEBUG):
41+
logger.debug('Status: "{}"'.format(self.msg))
3842
self.cursesScreen.refresh()
3943
if thread_lock is not None:
4044
thread_lock.release()
@@ -54,6 +58,8 @@ def write_right(self, msg, thread_lock=None):
5458
except:
5559
a_msg = msg.encode('utf-8', 'replace').strip()
5660
self.cursesScreen.addstr(0, self.width + 5 - len(a_msg) - 1, a_msg.replace("\r", "").replace("\n", ""))
61+
if logger.isEnabledFor(logging.DEBUG):
62+
logger.debug('Status right: "{}"'.format(a_msg))
5763
self.cursesScreen.refresh()
5864
if thread_lock is not None:
5965
thread_lock.release()

0 commit comments

Comments
 (0)