From c8ccc9649f9804050129ec277c8db7e3c2527b8d Mon Sep 17 00:00:00 2001 From: jonnieZG Date: Thu, 3 Dec 2020 08:42:00 +0100 Subject: [PATCH 1/4] - Station UUIDs used by radiobrowser are translated into shorter strings, to work with some older radios - Fixed radiobrowser service stations/byuuid/ REST method name - Version bumped to 1.1.1 --- ycast/__init__.py | 2 +- ycast/generic.py | 11 +++++++++++ ycast/my_stations.py | 15 +-------------- ycast/radiobrowser.py | 19 +++++++++++++++---- 4 files changed, 28 insertions(+), 19 deletions(-) diff --git a/ycast/__init__.py b/ycast/__init__.py index 1a72d32..b3ddbc4 100644 --- a/ycast/__init__.py +++ b/ycast/__init__.py @@ -1 +1 @@ -__version__ = '1.1.0' +__version__ = '1.1.1' diff --git a/ycast/generic.py b/ycast/generic.py index 0ef42a1..dcbe209 100644 --- a/ycast/generic.py +++ b/ycast/generic.py @@ -1,5 +1,6 @@ import logging import os +import hashlib USER_AGENT = 'YCast' VAR_PATH = os.path.expanduser("~") + '/.ycast' @@ -50,3 +51,13 @@ def get_cache_path(cache_name): logging.error("Could not create cache folders (%s) because of access permissions", cache_path) return None return cache_path + +def get_checksum(feed, charlimit=12): + hash_feed = feed.encode() + hash_object = hashlib.md5(hash_feed) + digest = hash_object.digest() + xor_fold = bytearray(digest[:8]) + for i, b in enumerate(digest[8:]): + xor_fold[i] ^= b + digest_xor_fold = ''.join(format(x, '02x') for x in bytes(xor_fold)) + return digest_xor_fold[:charlimit] diff --git a/ycast/my_stations.py b/ycast/my_stations.py index 64df667..25e8e44 100644 --- a/ycast/my_stations.py +++ b/ycast/my_stations.py @@ -1,6 +1,4 @@ import logging -import hashlib - import yaml import ycast.vtuner as vtuner @@ -71,17 +69,6 @@ def get_stations_by_category(category): if my_stations_yaml and category in my_stations_yaml: for station_name in my_stations_yaml[category]: station_url = my_stations_yaml[category][station_name] - station_id = str(get_checksum(station_name + station_url)).upper() + station_id = str(generic.get_checksum(station_name + station_url)).upper() stations.append(Station(station_id, station_name, station_url, category)) return stations - - -def get_checksum(feed, charlimit=12): - hash_feed = feed.encode() - hash_object = hashlib.md5(hash_feed) - digest = hash_object.digest() - xor_fold = bytearray(digest[:8]) - for i, b in enumerate(digest[8:]): - xor_fold[i] ^= b - digest_xor_fold = ''.join(format(x, '02x') for x in bytes(xor_fold)) - return digest_xor_fold[:charlimit] diff --git a/ycast/radiobrowser.py b/ycast/radiobrowser.py index b220884..5696b22 100644 --- a/ycast/radiobrowser.py +++ b/ycast/radiobrowser.py @@ -13,6 +13,7 @@ SHOW_BROKEN_STATIONS = False ID_PREFIX = "RB" +id_registry = {} def get_json_attr(json, attr): try: @@ -23,7 +24,7 @@ def get_json_attr(json, attr): class Station: def __init__(self, station_json): - self.id = generic.generate_stationid_with_prefix(get_json_attr(station_json, 'stationuuid'), ID_PREFIX) + self.id = get_json_attr(station_json, 'stationuuid') self.name = get_json_attr(station_json, 'name') self.url = get_json_attr(station_json, 'url') self.icon = get_json_attr(station_json, 'favicon') @@ -35,12 +36,14 @@ def __init__(self, station_json): self.bitrate = get_json_attr(station_json, 'bitrate') def to_vtuner(self): - return vtuner.Station(self.id, self.name, ', '.join(self.tags), self.url, self.icon, + tid = generic.get_checksum(self.id) + id_registry[tid] = self.id; + return vtuner.Station(generic.generate_stationid_with_prefix(tid, ID_PREFIX), self.name, ', '.join(self.tags), self.url, self.icon, self.tags[0], self.countrycode, self.codec, self.bitrate, None) def get_playable_url(self): try: - playable_url_json = request('url/' + generic.get_stationid_without_prefix(self.id))[0] + playable_url_json = request('url/' + str(self.id))[0] self.url = playable_url_json['url'] except (IndexError, KeyError): logging.error("Could not retrieve first playlist item for station with id '%s'", self.id) @@ -61,7 +64,7 @@ def request(url): def get_station_by_id(uid): - station_json = request('stations/byid/' + str(uid)) + station_json = request('stations/byuuid/' + str(id_registry[uid])) if station_json and len(station_json): return Station(station_json[0]) else: @@ -69,6 +72,7 @@ def get_station_by_id(uid): def search(name, limit=DEFAULT_STATION_LIMIT): + id_registry.clear() stations = [] stations_json = request('stations/search?order=name&reverse=false&limit=' + str(limit) + '&name=' + str(name)) for station_json in stations_json: @@ -78,6 +82,7 @@ def search(name, limit=DEFAULT_STATION_LIMIT): def get_country_directories(): + id_registry.clear() country_directories = [] apicall = 'countries' if not SHOW_BROKEN_STATIONS: @@ -92,6 +97,7 @@ def get_country_directories(): def get_language_directories(): + id_registry.clear() language_directories = [] apicall = 'languages' if not SHOW_BROKEN_STATIONS: @@ -107,6 +113,7 @@ def get_language_directories(): def get_genre_directories(): + id_registry.clear() genre_directories = [] apicall = 'tags' if not SHOW_BROKEN_STATIONS: @@ -122,6 +129,7 @@ def get_genre_directories(): def get_stations_by_country(country): + id_registry.clear() stations = [] stations_json = request('stations/search?order=name&reverse=false&countryExact=true&country=' + str(country)) for station_json in stations_json: @@ -131,6 +139,7 @@ def get_stations_by_country(country): def get_stations_by_language(language): + id_registry.clear() stations = [] stations_json = request('stations/search?order=name&reverse=false&languageExact=true&language=' + str(language)) for station_json in stations_json: @@ -140,6 +149,7 @@ def get_stations_by_language(language): def get_stations_by_genre(genre): + id_registry.clear() stations = [] stations_json = request('stations/search?order=name&reverse=false&tagExact=true&tag=' + str(genre)) for station_json in stations_json: @@ -149,6 +159,7 @@ def get_stations_by_genre(genre): def get_stations_by_votes(limit=DEFAULT_STATION_LIMIT): + id_registry.clear() stations = [] stations_json = request('stations?order=votes&reverse=true&limit=' + str(limit)) for station_json in stations_json: From 57545693e088ec86f0de1947ab2563014b6e9492 Mon Sep 17 00:00:00 2001 From: jonnieZG Date: Fri, 4 Dec 2020 20:50:49 +0100 Subject: [PATCH 2/4] - Fixed error in case there is no entry found in id_registry - Corrected logging levels for some entries - Added oyaml into setup.py --- setup.py | 2 +- ycast/my_stations.py | 2 +- ycast/radiobrowser.py | 14 ++++++++------ ycast/server.py | 2 +- ycast/station_icons.py | 4 ++-- 5 files changed, 13 insertions(+), 11 deletions(-) diff --git a/setup.py b/setup.py index 9d70bb7..f18a3ce 100644 --- a/setup.py +++ b/setup.py @@ -40,6 +40,6 @@ 'onkyo', 'denon' ], - install_requires=['requests', 'flask', 'PyYAML', 'Pillow'], + install_requires=['requests', 'flask', 'PyYAML', 'Pillow', 'oyaml'], packages=find_packages(exclude=['contrib', 'docs', 'tests']) ) diff --git a/ycast/my_stations.py b/ycast/my_stations.py index 25e8e44..032b3af 100644 --- a/ycast/my_stations.py +++ b/ycast/my_stations.py @@ -1,5 +1,5 @@ import logging -import yaml +import oyaml as yaml import ycast.vtuner as vtuner import ycast.generic as generic diff --git a/ycast/radiobrowser.py b/ycast/radiobrowser.py index 5696b22..87c1a2f 100644 --- a/ycast/radiobrowser.py +++ b/ycast/radiobrowser.py @@ -37,7 +37,7 @@ def __init__(self, station_json): def to_vtuner(self): tid = generic.get_checksum(self.id) - id_registry[tid] = self.id; + id_registry[tid] = self.id return vtuner.Station(generic.generate_stationid_with_prefix(tid, ID_PREFIX), self.name, ', '.join(self.tags), self.url, self.icon, self.tags[0], self.countrycode, self.codec, self.bitrate, None) @@ -64,10 +64,13 @@ def request(url): def get_station_by_id(uid): - station_json = request('stations/byuuid/' + str(id_registry[uid])) - if station_json and len(station_json): - return Station(station_json[0]) - else: + try: + station_json = request('stations/byuuid/' + str(id_registry[uid])) + if station_json and len(station_json): + return Station(station_json[0]) + else: + return None + except KeyError: return None @@ -163,7 +166,6 @@ def get_stations_by_votes(limit=DEFAULT_STATION_LIMIT): stations = [] stations_json = request('stations?order=votes&reverse=true&limit=' + str(limit)) for station_json in stations_json: - print(station_json) if SHOW_BROKEN_STATIONS or get_json_attr(station_json, 'lastcheckok') == 1: stations.append(Station(station_json)) return stations diff --git a/ycast/server.py b/ycast/server.py index 6d963da..dcdffee 100644 --- a/ycast/server.py +++ b/ycast/server.py @@ -304,7 +304,7 @@ def get_station_icon(): abort(404) station_icon = station_icons.get_icon(station) if not station_icon: - logging.error("Could not get station icon for station with id '%s'", stationid) + logging.warning("Could not get station icon for station with id '%s'", stationid) abort(404) response = make_response(station_icon) response.headers.set('Content-Type', 'image/jpeg') diff --git a/ycast/station_icons.py b/ycast/station_icons.py index 3c79ce7..e072024 100644 --- a/ycast/station_icons.py +++ b/ycast/station_icons.py @@ -23,10 +23,10 @@ def get_icon(station): try: response = requests.get(station.icon, headers=headers) except requests.exceptions.ConnectionError as err: - logging.error("Connection to station icon URL failed (%s)", err) + logging.debug("Connection to station icon URL failed (%s)", err) return None if response.status_code != 200: - logging.error("Could not get station icon data from %s (HTML status %s)", station.icon, response.status_code) + logging.debug("Could not get station icon data from %s (HTML status %s)", station.icon, response.status_code) return None try: image = Image.open(io.BytesIO(response.content)) From 11a97c24a49800142f2bff4e85d4ae69502ecf8b Mon Sep 17 00:00:00 2001 From: jonnieZG Date: Fri, 4 Dec 2020 20:51:37 +0100 Subject: [PATCH 3/4] Added .vscode to .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 0855b89..741cc2c 100644 --- a/.gitignore +++ b/.gitignore @@ -2,5 +2,6 @@ build dist *.egg-info .idea +.vscode *.iml *.pyc From 05a2b1ed1f689975b749a63cc69e62b0061e9e20 Mon Sep 17 00:00:00 2001 From: jonnieZG Date: Fri, 4 Dec 2020 20:51:37 +0100 Subject: [PATCH 4/4] Added .vscode to .gitignore Version back to milaq's 1.1.0 --- .gitignore | 1 + ycast/__init__.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 0855b89..741cc2c 100644 --- a/.gitignore +++ b/.gitignore @@ -2,5 +2,6 @@ build dist *.egg-info .idea +.vscode *.iml *.pyc diff --git a/ycast/__init__.py b/ycast/__init__.py index b3ddbc4..1a72d32 100644 --- a/ycast/__init__.py +++ b/ycast/__init__.py @@ -1 +1 @@ -__version__ = '1.1.1' +__version__ = '1.1.0'