From 7c3161aff96e251da1b2695a2345540b016928c5 Mon Sep 17 00:00:00 2001 From: milaq Date: Thu, 22 Aug 2019 20:30:29 +0200 Subject: [PATCH] Make YCast aware of played streams Every stream URL is may now be fetched from the YCast server via redirection. This allows for future integration of a "recently played" functionality and an availability check. --- ycast/server.py | 58 ++++++++++++++++++++++++++++++++++++------------- ycast/vtuner.py | 9 +++++++- 2 files changed, 51 insertions(+), 16 deletions(-) diff --git a/ycast/server.py b/ycast/server.py index 0d10d40..c47b505 100644 --- a/ycast/server.py +++ b/ycast/server.py @@ -5,9 +5,11 @@ from flask import Flask, request, url_for, redirect, abort import ycast.vtuner as vtuner import ycast.radiobrowser as radiobrowser import ycast.my_stations as my_stations +import ycast.generic as generic PATH_ROOT = 'ycast' +PATH_PLAY = 'play' PATH_SEARCH = 'search' PATH_MY_STATIONS = 'my_stations' PATH_RADIOBROWSER = 'radiobrowser' @@ -33,12 +35,12 @@ def check_my_stations_feature(config): my_stations_enabled = my_stations.set_config(config) -def get_directories_page(subdir, directories, requestargs): +def get_directories_page(subdir, directories, request): page = vtuner.Page() if len(directories) == 0: page.add(vtuner.Display("No entries found.")) return page - for directory in get_paged_elements(directories, requestargs): + for directory in get_paged_elements(directories, request.args): vtuner_directory = vtuner.Directory(directory.name, url_for(subdir, _external=True, directory=directory.name), directory.item_count) page.add(vtuner_directory) @@ -46,13 +48,16 @@ def get_directories_page(subdir, directories, requestargs): return page -def get_stations_page(stations, requestargs): +def get_stations_page(stations, request, tracked=True): page = vtuner.Page() if len(stations) == 0: page.add(vtuner.Display("No stations found.")) return page - for station in get_paged_elements(stations, requestargs): - page.add(station.to_vtuner()) + for station in get_paged_elements(stations, request.args): + vtuner_station = station.to_vtuner() + if tracked: + vtuner_station.set_trackurl(request.host_url + PATH_ROOT + '/' + PATH_PLAY + '?id=' + vtuner_station.uid) + page.add(vtuner_station) page.set_count(len(stations)) return page @@ -81,6 +86,15 @@ def get_paged_elements(items, requestargs): return items[offset:limit] +def get_station_by_id(stationid): + station_id_prefix = generic.get_stationid_prefix(stationid) + if station_id_prefix == my_stations.ID_PREFIX: + return my_stations.get_station_by_id(generic.get_stationid_without_prefix(stationid)) + elif station_id_prefix == radiobrowser.ID_PREFIX: + return radiobrowser.get_station_by_id(generic.get_stationid_without_prefix(stationid)) + return None + + @app.route('/setupapp/') def upstream(path): if request.args.get('token') == '0': @@ -111,13 +125,13 @@ def my_stations_landing(): page = vtuner.Page() page.add(vtuner.Previous(url_for("landing", _external=True))) directories = my_stations.get_category_directories() - return get_directories_page('my_stations_category', directories, request.args).to_string() + return get_directories_page('my_stations_category', directories, request).to_string() @app.route('/' + PATH_ROOT + '/' + PATH_MY_STATIONS + '/') def my_stations_category(directory): stations = my_stations.get_stations_by_category(directory) - return get_stations_page(stations, request.args).to_string() + return get_stations_page(stations, request).to_string() @app.route('/' + PATH_ROOT + '/' + PATH_RADIOBROWSER + '/') @@ -138,43 +152,43 @@ def radiobrowser_landing(): @app.route('/' + PATH_ROOT + '/' + PATH_RADIOBROWSER + '/' + PATH_RADIOBROWSER_COUNTRY + '/') def radiobrowser_countries(): directories = radiobrowser.get_country_directories() - return get_directories_page('radiobrowser_country_stations', directories, request.args).to_string() + return get_directories_page('radiobrowser_country_stations', directories, request).to_string() @app.route('/' + PATH_ROOT + '/' + PATH_RADIOBROWSER + '/' + PATH_RADIOBROWSER_COUNTRY + '/') def radiobrowser_country_stations(directory): stations = radiobrowser.get_stations_by_country(directory) - return get_stations_page(stations, request.args).to_string() + return get_stations_page(stations, request).to_string() @app.route('/' + PATH_ROOT + '/' + PATH_RADIOBROWSER + '/' + PATH_RADIOBROWSER_LANGUAGE + '/') def radiobrowser_languages(): directories = radiobrowser.get_language_directories() - return get_directories_page('radiobrowser_language_stations', directories, request.args).to_string() + return get_directories_page('radiobrowser_language_stations', directories, request).to_string() @app.route('/' + PATH_ROOT + '/' + PATH_RADIOBROWSER + '/' + PATH_RADIOBROWSER_LANGUAGE + '/') def radiobrowser_language_stations(directory): stations = radiobrowser.get_stations_by_language(directory) - return get_stations_page(stations, request.args).to_string() + return get_stations_page(stations, request).to_string() @app.route('/' + PATH_ROOT + '/' + PATH_RADIOBROWSER + '/' + PATH_RADIOBROWSER_GENRE + '/') def radiobrowser_genres(): directories = radiobrowser.get_genre_directories() - return get_directories_page('radiobrowser_genre_stations', directories, request.args).to_string() + return get_directories_page('radiobrowser_genre_stations', directories, request).to_string() @app.route('/' + PATH_ROOT + '/' + PATH_RADIOBROWSER + '/' + PATH_RADIOBROWSER_GENRE + '/') def radiobrowser_genre_stations(directory): stations = radiobrowser.get_stations_by_genre(directory) - return get_stations_page(stations, request.args).to_string() + return get_stations_page(stations, request).to_string() @app.route('/' + PATH_ROOT + '/' + PATH_RADIOBROWSER + '/' + PATH_RADIOBROWSER_POPULAR + '/') def radiobrowser_popular(): stations = radiobrowser.get_stations_by_votes() - return get_stations_page(stations, request.args).to_string() + return get_stations_page(stations, request).to_string() @app.route('/' + PATH_ROOT + '/' + PATH_SEARCH + '/') @@ -189,4 +203,18 @@ def station_search(): else: # TODO: we also need to include 'my station' elements stations = radiobrowser.search(query) - return get_stations_page(stations, request.args).to_string() + return get_stations_page(stations, request).to_string() + + +@app.route('/' + PATH_ROOT + '/' + PATH_PLAY) +def get_stream_url(): + stationid = request.args.get('id') + if not stationid: + logging.error("Stream URL without station ID requested") + abort(400) + station = get_station_by_id(stationid) + if not station: + logging.error("Could not get station with id '%s'", stationid) + abort(404) + logging.debug("Station with ID '%s' requested", station.id) + return redirect(station.url, code=302) diff --git a/ycast/vtuner.py b/ycast/vtuner.py index fe8af00..ccde536 100644 --- a/ycast/vtuner.py +++ b/ycast/vtuner.py @@ -110,6 +110,7 @@ class Station: self.name = name self.description = description self.url = strip_https(url) + self.trackurl = None self.logo = logo self.genre = genre self.location = location @@ -117,12 +118,18 @@ class Station: self.bitrate = bitrate self.bookmark = bookmark + def set_trackurl(self, url): + self.trackurl = url + def to_xml(self): item = ET.Element('Item') ET.SubElement(item, 'ItemType').text = 'Station' ET.SubElement(item, 'StationId').text = self.uid ET.SubElement(item, 'StationName').text = self.name - ET.SubElement(item, 'StationUrl').text = self.url + if self.trackurl: + ET.SubElement(item, 'StationUrl').text = self.trackurl + else: + ET.SubElement(item, 'StationUrl').text = self.url ET.SubElement(item, 'StationDesc').text = self.description ET.SubElement(item, 'Logo').text = self.logo ET.SubElement(item, 'StationFormat').text = self.genre