Overhaul of filter/limits.
Documented format in filter.yml.example. Bumped the version number to 1.3.0. Added example api calls.
This commit is contained in:
parent
a54bdf050a
commit
f716d8ecd2
7 changed files with 167 additions and 32 deletions
|
@ -149,9 +149,9 @@ Category two name:
|
|||
You can also have a look at the provided [example](examples/stations.yml.example) to better understand the configuration.
|
||||
|
||||
### Filter/limits
|
||||
The filter configuration file .ycast/filter.yml (see example) allows to filter stations based on a whitelist / blacklist. The contents of this list specifies which attributes to filter on.
|
||||
The filter configuration file .ycast/filter.ymlallows to filter stations based on a whitelist / blacklist. The contents of this list specifies which attributes to filter on. Look at the provided [example](examples/filter.yml.examepl) for the configuration details.
|
||||
|
||||
The limits allow to filter out genres, countries and languages that fail to have a certain amount of items. It also sets the default station limit and allows to show or hide broken stations. Defaults are as follows:
|
||||
The limits allow to filter out genres, countries and languages that fail to have a certain amount of items. It also sets the default station limit for search and votes and allows to show or hide broken stations. Defaults are as follows:
|
||||
* MINIMUM_COUNT_GENRE : 40
|
||||
* MINIMUM_COUNT_COUNTRY : 5
|
||||
* MINIMUM_COUNT_LANGUAGE : 5
|
||||
|
|
24
examples/apicalls.sh
Normal file
24
examples/apicalls.sh
Normal file
|
@ -0,0 +1,24 @@
|
|||
ENDPOINT=127.0.0.1
|
||||
# API
|
||||
# Get recently played stations
|
||||
curl "http://${ENDPOINT}/api/stations?category=recently"
|
||||
# Get highest rated stations
|
||||
curl "http://${ENDPOINT}/api/stations?category=voted"
|
||||
# Get stations by language, specify by language paramter (default=german)
|
||||
curl "http://${ENDPOINT}/api/stations?category=language&language=dutch"
|
||||
# Get stations by country, specify by country paramter (default=Germany)
|
||||
curl "http://${ENDPOINT}/api/stations?category=country&country=The%20Netherlands"
|
||||
|
||||
# Ycast XML calls
|
||||
curl "http://${ENDPOINT}/setupapp"
|
||||
# Search by name
|
||||
curl "http://${ENDPOINT}/ycast/search/?search=Pinguin"
|
||||
# List top directories (Genres, Countries, Languages, Most Popular).
|
||||
curl "http://${ENDPOINT}/ycast/radiobrowser/"
|
||||
# Play station
|
||||
curl "http://${ENDPOINT}/ycast/play?id=stationid"
|
||||
# Get station info
|
||||
curl "http://${ENDPOINT}/ycast/station?id=stationid"
|
||||
curl "http://${ENDPOINT}/ycast/icon?id=stationid"
|
||||
# Get station icon
|
||||
|
|
@ -1,7 +1,53 @@
|
|||
blacklist:
|
||||
favicon: ''
|
||||
# Filters can be applied to the search results coming back from
|
||||
# api.radio-browser.info. Results can either be whitelisted or blacklisted. The
|
||||
# attributes in the whitelist are actually the attributes of the Station Struct
|
||||
# defined here: https://de1.api.radio-browser.info/#Struct_station. The most
|
||||
# useful ones to filter on are: codec, bitrate, language, languagecode. Ycast
|
||||
# has a default whitelist for the lastcheckok attribute to be set (1) which
|
||||
# indicates the stream is currently operational, as it does not make sense to
|
||||
# return stations to the AV receiver that are broken. There are a few
|
||||
# attributes that have a multi value string, the values are separated by a
|
||||
# comma (,) (imo this should be a json list so clients don't have to parse the
|
||||
# string, but it is as it is). The filter code will split these strings into a
|
||||
# list first and then will try to match the the value from the whitelist or
|
||||
# blacklist on any of the values in the list. The most interesting multi value
|
||||
# attribute is the tags attribute which carries the genre(s) of the station.
|
||||
# Unfortunately the values are rather free format, so there is no fixed list of
|
||||
# genres to filter on and most stations indicate multiple genres. Attribute
|
||||
# filter values can be either a single or multi-value. Multi-values
|
||||
# should be entered in the filter file as a json list, either using the bracket
|
||||
# ([]) or list (-) syntax. See the examples below.
|
||||
#
|
||||
# For the directory listings by Genre, Language, Country the following filter
|
||||
# attributes will be applied: Genre: tags; Language: languagecodes; Country:
|
||||
# country.
|
||||
|
||||
whitelist:
|
||||
country: Germany
|
||||
countrycode: DE,US,NO,GB
|
||||
languagecodes: en,no
|
||||
lastcheckok: 1
|
||||
#Filter on the full country name:
|
||||
#country: Germany
|
||||
#Filter on any of the country codes specified in this [] list:
|
||||
#countrycode: [ "DE","US","NO","GB" ]
|
||||
#Filter on any of the language codes specified in this - list:
|
||||
#languagecodes:
|
||||
# - "en"
|
||||
# - "no"
|
||||
# Filter on bitrate:
|
||||
#bitrate: 192
|
||||
#To override the lastcheckok default (1) use this:
|
||||
#lastcheckok: [ 0,1 ]
|
||||
blacklist:
|
||||
# Filter out stations with no favicon:
|
||||
favicon: ''
|
||||
# Filter on codecs:
|
||||
#codec: ["AAC", "AAC+"]
|
||||
# Limits can be applied, below are the hardcoded defautls, which can be overridden in this file.
|
||||
#limits:
|
||||
# The following limits will be applied to the directory listing of genre, country and language. Each item should contain this minium amount of entries to be returned.
|
||||
#MINIMUM_COUNT_GENRE: 40
|
||||
#MINIMUM_COUNT_COUNTRY: 5
|
||||
#MINIMUM_COUNT_LANGUAGE: 5
|
||||
# The default maximum amount of entries to return from search and search by
|
||||
# votes.
|
||||
#DEFAULT_STATION_LIMIT: 200
|
||||
# Include broken stations in the result.
|
||||
#SHOW_BROKEN_STATIONS: False
|
||||
|
|
|
@ -1 +1 @@
|
|||
__version__ = '1.2.4'
|
||||
__version__ = '1.3.0'
|
||||
|
|
|
@ -20,13 +20,19 @@ def init_filter_file():
|
|||
filter_dictionary = {}
|
||||
is_updated = True
|
||||
if 'whitelist' in filter_dictionary:
|
||||
# Copy dict items to keep the 1 default item
|
||||
for f in filter_dictionary['whitelist']:
|
||||
white_list[f]=filter_dictionary['whitelist'][f]
|
||||
if filter_dictionary['whitelist'] is None:
|
||||
white_list = { "lastcheckok" : 1}
|
||||
else:
|
||||
# Copy so the default is preserved.
|
||||
for f in filter_dictionary['whitelist']:
|
||||
white_list[f]=filter_dictionary['whitelist'][f]
|
||||
|
||||
if 'blacklist' in filter_dictionary:
|
||||
# reference, no defaults
|
||||
black_list = filter_dictionary['blacklist']
|
||||
if filter_dictionary['blacklist'] is None:
|
||||
black_list={}
|
||||
else:
|
||||
black_list=filter_dictionary['blacklist']
|
||||
|
||||
if 'limits' in filter_dictionary:
|
||||
set_limits(filter_dictionary['limits'])
|
||||
|
@ -68,14 +74,24 @@ def parameter_failed_evt(param_name):
|
|||
|
||||
|
||||
def verify_value(ref_val, val):
|
||||
if ref_val == val:
|
||||
return True
|
||||
if ref_val is None:
|
||||
return len(val) == 0
|
||||
if type(val) is int:
|
||||
return val == int(ref_val)
|
||||
if val:
|
||||
return ref_val.find(val) >= 0
|
||||
if isinstance(val, str) and val.find(",") > -1:
|
||||
val_list=val.split(",")
|
||||
else:
|
||||
val_list=[val]
|
||||
|
||||
for v in val_list:
|
||||
if v == None:
|
||||
v=''
|
||||
if isinstance(ref_val, list):
|
||||
return v in ref_val
|
||||
if str(ref_val) == str(v):
|
||||
return True
|
||||
if ref_val is None:
|
||||
return len(v) == 0
|
||||
# if type(val) is int:
|
||||
## return val == int(ref_val)
|
||||
# if val:
|
||||
# return ref_val.find(str(val)) >= 0
|
||||
return False
|
||||
|
||||
|
||||
|
|
|
@ -88,7 +88,6 @@ def get_station_by_id(vtune_id):
|
|||
|
||||
|
||||
def get_country_directories():
|
||||
begin_filter()
|
||||
country_directories = []
|
||||
apicall = 'countries'
|
||||
if not get_limit('SHOW_BROKEN_STATIONS'):
|
||||
|
@ -104,7 +103,6 @@ def get_country_directories():
|
|||
|
||||
|
||||
def get_language_directories():
|
||||
begin_filter()
|
||||
language_directories = []
|
||||
apicall = 'languages'
|
||||
if not get_limit('SHOW_BROKEN_STATIONS'):
|
||||
|
@ -129,7 +127,8 @@ def get_genre_directories():
|
|||
for genre_raw in genres_raw:
|
||||
if get_json_attr(genre_raw, 'name') and get_json_attr(genre_raw, 'stationcount') and \
|
||||
int(get_json_attr(genre_raw, 'stationcount')) > get_limit('MINIMUM_COUNT_GENRE'):
|
||||
genre_directories.append(generic.Directory(get_json_attr(genre_raw, 'name'),
|
||||
if my_filter.chk_parameter('tags', get_json_attr(genre_raw, 'name')):
|
||||
genre_directories.append(generic.Directory(get_json_attr(genre_raw, 'name'),
|
||||
get_json_attr(genre_raw, 'stationcount'),
|
||||
get_json_attr(genre_raw, 'name').capitalize()))
|
||||
return genre_directories
|
||||
|
|
|
@ -18,19 +18,23 @@ class MyTestCase(unittest.TestCase):
|
|||
|
||||
def test_verify_values(self):
|
||||
assert my_filter.verify_value(None, None)
|
||||
assert my_filter.verify_value('', None)
|
||||
assert my_filter.verify_value('', '')
|
||||
assert my_filter.verify_value(None, '')
|
||||
assert my_filter.verify_value(3, 3)
|
||||
assert my_filter.verify_value('3', 3)
|
||||
assert my_filter.verify_value('3', '3')
|
||||
assert my_filter.verify_value('3,4,5,6', '5')
|
||||
assert my_filter.verify_value('3', '3,4,5')
|
||||
assert my_filter.verify_value(['3','5'], '3')
|
||||
assert my_filter.verify_value(['3','5'], '3,6')
|
||||
assert my_filter.verify_value([3,4,5,6], 5)
|
||||
|
||||
assert not my_filter.verify_value('', None)
|
||||
assert not my_filter.verify_value('', '3')
|
||||
assert not my_filter.verify_value(3, 4)
|
||||
assert not my_filter.verify_value('3', 4)
|
||||
assert not my_filter.verify_value('4', '3')
|
||||
assert not my_filter.verify_value('3,4,5,6', '9')
|
||||
assert not my_filter.verify_value(['3,4,5,6'], '9')
|
||||
assert not my_filter.verify_value(['3,4,5,6'], '9,8')
|
||||
|
||||
def test_init_filter(self):
|
||||
my_filter.begin_filter()
|
||||
|
@ -44,26 +48,72 @@ class MyTestCase(unittest.TestCase):
|
|||
else:
|
||||
logging.warning(" <empty list>")
|
||||
|
||||
def test_life_popular_station(self):
|
||||
def test_station_search(self):
|
||||
# hard test for filter
|
||||
stations = radiobrowser.get_stations_by_votes(10000000)
|
||||
my_filter.white_list={}
|
||||
my_filter.black_list={}
|
||||
stations = radiobrowser.search('Pinguin Pop')
|
||||
logging.info("Stations found (%d)", len(stations))
|
||||
assert len(stations) == 1
|
||||
my_filter.white_list={}
|
||||
my_filter.black_list={ "countrycode": 'NL'}
|
||||
stations = radiobrowser.search('Pinguin Pop')
|
||||
logging.info("Stations found (%d)", len(stations))
|
||||
assert len(stations) == 0
|
||||
|
||||
def test_station_by_country(self):
|
||||
my_filter.white_list={ "codec" : "OGG" }
|
||||
my_filter.black_list={ }
|
||||
stations = radiobrowser.get_stations_by_country('Germany')
|
||||
logging.info("Stations (%d)", len(stations))
|
||||
# Currently yields 40 but is not fixed of course
|
||||
assert len(stations) > 20 and len(stations) < 70
|
||||
|
||||
def test_station_by_language(self):
|
||||
my_filter.white_list={ "codec" : "AAC"}
|
||||
my_filter.black_list={"countrycode": "NL"}
|
||||
stations = radiobrowser.get_stations_by_language('dutch')
|
||||
logging.info("Stations (%d)", len(stations))
|
||||
# With this filter there is only 1 (atm).
|
||||
assert len(stations) == 1
|
||||
|
||||
def test_station_by_genre(self):
|
||||
my_filter.white_list={"bitrate" : 320}
|
||||
my_filter.black_list={}
|
||||
stations = radiobrowser.get_stations_by_genre('rock')
|
||||
logging.info("Stations (%d)", len(stations))
|
||||
# Currently yields 86 but is not fixed of course
|
||||
assert len(stations) > 50 and len(stations) < 100
|
||||
|
||||
def test_station_by_votes(self):
|
||||
my_filter.white_list={}
|
||||
my_filter.black_list={}
|
||||
stations = radiobrowser.get_stations_by_votes()
|
||||
logging.info("Stations (%d)", len(stations))
|
||||
assert len(stations) == my_filter.get_limit('DEFAULT_STATION_LIMIT')
|
||||
#stations = radiobrowser.get_stations_by_votes(10000)
|
||||
#logging.info("Stations (%d)", len(stations))
|
||||
#assert len(stations) == 10000
|
||||
|
||||
def test_get_languages(self):
|
||||
my_filter.white_list={ 'languagecodes' : ['en','no'] }
|
||||
my_filter.black_list={}
|
||||
result = radiobrowser.get_language_directories()
|
||||
logging.info("Languages (%d)", len(result))
|
||||
# Based on the example filter is should yield 2
|
||||
assert len(result) == 2
|
||||
|
||||
def test_get_countries(self):
|
||||
my_filter.init_filter_file()
|
||||
# Test for Germany only 1, nach der Wiedervereinigung...
|
||||
my_filter.white_list={ 'country' : 'Germany' }
|
||||
my_filter.black_list={}
|
||||
|
||||
result = radiobrowser.get_country_directories()
|
||||
logging.info("Countries (%d)", len(result))
|
||||
# Test for Germany only 1, nach der Wiedervereinigung...
|
||||
assert len(result) == 1
|
||||
|
||||
def test_get_genre(self):
|
||||
my_filter.white_list={ 'tags' : ['rock','pop'] }
|
||||
my_filter.black_list={}
|
||||
result = radiobrowser.get_genre_directories()
|
||||
logging.info("Genres (%d)", len(result))
|
||||
# Not a useful test, changes all the time
|
||||
|
|
Loading…
Add table
Reference in a new issue