Skip to content
Permalink
Browse files

Migration to python 3, courtesy of Chris Branner

  • Loading branch information...
Christopher Brannon authored and halhen committed Nov 4, 2010
1 parent 43c9ef9 commit 95fca164d0ec12f5c0cde1345c83e80841b307db
Showing with 51 additions and 44 deletions.
  1. +5 −0 AUTHORS
  2. +32 −32 shoutcast-search
  3. +1 −1 shoutcast_search/__init__.py
  4. +13 −11 shoutcast_search/shoutcast_search.py
@@ -0,0 +1,5 @@
Author of shoutcast-search:
Henrik Hallberg <halhen@k2h.se> 2009-2010

Migration from python2 to python3:
Christopher Brannon <chris AT the-brannons DOT com> 2010
@@ -24,7 +24,7 @@

import re
import sys
import urllib2
import urllib.error
import random
import optparse

@@ -52,25 +52,25 @@ def _station_text(station_info, format):
return resstr

def _fail_exit(code, msg):
sys.stderr.write("%s: %s\n" % (sys.argv[0], msg))
sys.stderr.write("{0}: {1}\n".format(sys.argv[0], msg))
sys.exit(code)

def _expression_param(value):
if not value:
return lambda(x):True
return lambda x:True
if not re.compile('^[=><]?\d+$').match(value):
o.error('invalid expression: %s' % value)
o.error('invalid expression: {0}'.format(value))

if value[0] in ('><'):
return lambda(x): eval('%s%s' % (x, value))
return lambda x: eval('{0}{1}'.format(x, value))
else:
return lambda(x): eval('%s==%s' % (x, value.strip('=')))
return lambda x: eval('{0}=={1}'.format(x, value.strip('=')))

def _int_param(value):
try:
return int(value)
except:
o.error('invalid integer: %s' % value)
o.error('invalid integer: {0}'.format(value))

def _generate_list_sorters(pattern = 'l'):
'''
@@ -97,7 +97,7 @@ def _generate_list_sorters(pattern = 'l'):
descending_text = 'desc'
if not descending:
descending_text = 'asc'
return '%s %s' % (fieldname, descending_text)
return '{0} {1}'.format(fieldname, descending_text)

def _random(list):
random.shuffle(list)
@@ -134,12 +134,12 @@ def _generate_list_sorters(pattern = 'l'):
index -= 1

if not number:
o.error('missing number for sorter n in "%s"' % pattern)
o.error('missing number for sorter n in "{0}"'.format(pattern))
value = int(number)
sorters.append(lambda list: list[:value])
sorters_description.append('top %s' % value)
sorters_description.append('top {0}'.format(value))
else:
o.error('invalid sorter: %s' % char)
o.error('invalid sorter: {0}'.format(char))

if char != '^':
sort_descending = True # Reset sort order
@@ -189,7 +189,7 @@ if __name__ == '__main__':
try:
if options.do_list_genres:
genres = scs.get_genres()
print '\n'.join(genres)
print('\n'.join(genres))
if genres:
sys.exit(0)
else:
@@ -224,43 +224,43 @@ if __name__ == '__main__':

if p_verbose:
# Print information about query to help debug
print 'Search summary'
print '-' * 30
print ' Keywords: %s' % ', '.join(p_keywords)
print ' Genres: %s' % ', '.join(p_genre)
print ' Playing: %s' % ', '.join(p_song)
print ' Stations: %s' % ', '.join(p_station)
print('Search summary')
print('-' * 30)
print(' Keywords: {0}'.format(', '.join(p_keywords)))
print(' Genres: {0}'.format(', '.join(p_genre)))
print(' Playing: {0}'.format(', '.join(p_song)))
print(' Stations: {0}'.format(', '.join(p_station)))
bitrate_str = ''
if options.bitrate:
bitrate_str = options.bitrate
print ' Bitrate: %s' % bitrate_str
print(' Bitrate: {0}'.format(bitrate_str))
listeners_str = ''
if options.listeners:
listeners_str = options.listeners
print 'Listeners: %s' % listeners_str
print ' Type: %s' % options.codec
print('Listeners: {0}'.format(listeners_str))
print(' Type: {0}'.format(options.codec))
order_str = 'by no listeners'
if p_random:
order_str = 'random'
if p_sort_rules:
order_str = 'by sorters'
print ' Order: %s' % order_str
print ' Sorter: %s' % (' | '.join(sorters_description))
print(' Order: {0}'.format(order_str))
print(' Sorter: {0}'.format(' | '.join(sorters_description)))
limit_str = ''
if p_limit > 0:
limit_str = str(p_limit)
print ' Limit: %s' % limit_str
print ' Format: %s' % p_format
print ''
print(' Limit: {0}'.format(limit_str))
print(' Format: {0}'.format(p_format))
print('')

results = scs.search(p_keywords, p_station, p_genre, p_song, p_bitrate, p_listeners, p_mime_type, p_limit, p_random, sorters)

print '\n'.join(_station_text(el, p_format) for el in results)
print('\n'.join(_station_text(el, p_format) for el in results))
if p_verbose:
print '\n%s station(s) found.' % len(results)
print('\n{0:d} station(s) found.'.format(len(results)))
if not results:
_fail_exit(4, 'no station found\n')
except urllib2.URLError, e:
_fail_exit(1, 'network error: %s' % e)
except Exception, e:
_fail_exit(3, 'unknown error: %s' % e)
except urllib.error.URLError as e:
_fail_exit(1, 'network error: {0}'.format(e))
except Exception as e:
_fail_exit(3, 'unknown error: {0}'.format(e))
@@ -21,7 +21,7 @@

__version__ = 'CURVERSION'

import shoutcast_search
from . import shoutcast_search

def main():
pass
@@ -21,34 +21,36 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#

import urllib
import urllib2
import urllib.request, urllib.parse, urllib.error
import re
import random
from htmlentitydefs import name2codepoint
from html.entities import name2codepoint

def _from_UTF_8(inbytes):
return str(inbytes, 'UTF-8')

def _build_search_url(params):
'''
Return URL to search web service with appropriately encoded parameters.
params - See urllib.urlencode
'''
baseurl = 'http://yp.shoutcast.com/sbin/newxml.phtml?'
params_str = urllib.urlencode(params)
params_str = urllib.parse.urlencode(params)
return baseurl + params_str

def _decode_entities(s):
'''
Return string with converted htmlentities, e.g. &auml;
s - string to convert
'''
return re.sub('&(%s);'% ('|'.join(name2codepoint)), lambda(m): chr(name2codepoint[m.group(1)]), s)
return re.sub('&(%s);'% ('|'.join(name2codepoint)), lambda m: chr(name2codepoint[m.group(1)]), s)

def _retrieve_search_results(params):
'''
Perform search against shoutcast.com web service.
params - See urllib.urlencode and http://forums.winamp.com/showthread.php?threadid=295638
'''
content = urllib2.urlopen(_build_search_url(params)).read()
content = _from_UTF_8(urllib.request.urlopen(_build_search_url(params)).read())

lp = re.compile('<station ')
p = re.compile(' (.*?)=\"(.*?)\"')
@@ -72,17 +74,17 @@ def url_by_id(index):
'''
Returns the stations URL based on its ID
'''
return 'http://yp.shoutcast.com/sbin/tunein-station.pls?id=%s' % index
return 'http://yp.shoutcast.com/sbin/tunein-station.pls?id={0}'.format(index)

def get_genres():
'''
Returns a list of genres (listed by the shoutcast web service).
Raises urllib2.URLError if network communication fails
'''
content = urllib2.urlopen('http://yp.shoutcast.com/sbin/newxml.phtml').read()
content = _from_UTF_8(urllib.request.urlopen('http://yp.shoutcast.com/sbin/newxml.phtml').read())
return list(re.compile('<genre name="(.*?)"').findall(content))

def search(search = [], station = [], genre = [], song = [], bitrate_fn = lambda(x): True, listeners_fn = lambda(x): True, mime_type = '', limit = 0, randomize = False, sorters = []):
def search(search = [], station = [], genre = [], song = [], bitrate_fn = lambda x: True, listeners_fn = lambda x: True, mime_type = '', limit = 0, randomize = False, sorters = []):
'''
Search shoutcast.com for streams with given criteria. See http://forums.winamp.com/showthread.php?threadid=295638 for details and rules. Raises urllib2.URLError if network communication fails.
search - List of free-form keywords. Searches in station names, genres and songs.
@@ -140,13 +142,13 @@ def search(search = [], station = [], genre = [], song = [], bitrate_fn = lambda
for s in song:
results = [r for r in results if s.upper() in r['ct'].upper()]
for k in keywords:
results = [r for r in results if k.upper() in ('%s %s %s' % (r['name'], r['genre'], r['ct'])).upper()]
results = [r for r in results if k.upper() in '{0} {1} {2}'.format(r['name'], r['genre'], r['ct']).upper()]

if randomize:
random.shuffle(results)
else:
# Sort by listener count
results.sort(lambda a, b: cmp(int(a['lc']), int(b['lc'])), reverse=True)
results.sort(key=lambda x: int(x['lc']), reverse=True)

for m in sorters:
results = m(results)

0 comments on commit 95fca16

Please sign in to comment.
You can’t perform that action at this time.