diff --git a/.all-contributorsrc b/.all-contributorsrc
index bb89f29..45e11ed 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -24,6 +24,16 @@
"contributions": [
"code"
]
+ },
+ {
+ "login": "marvoh",
+ "name": "marvoh",
+ "avatar_url": "https://avatars.githubusercontent.com/u/5451142?v=4",
+ "profile": "https://github.com/marvoh",
+ "contributions": [
+ "code",
+ "bug"
+ ]
}
],
"contributorsPerLine": 7,
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f76b635..59b0e36 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,14 @@
+## 2.9.0
+
+1. Fetch current playing track info from runtime commands 🎶 ⚡
+2. Sort results with several parameters like: click-count, popularity, bitrate, random etc. `--sort`
+3. Select stations from favorite menu to remove them `--remove`
+4. Result page will adjust width according to the actual terminal window size
+5. Squashed CTRL+D unhandled bugs
+6. Detect station name while playing with direct url
+7. Play a random station from result page
+8. See station information from runtime command
+
## 2.8.0
1. Selection menu added for `--country` and `--tag` results. Play directly from result page.
@@ -15,7 +26,7 @@
4. Runtime command feature added. Perform actions on demand ⚡
5. A caching mechanism was added for fewer API calls. Faster radio playbacks!
6. Code refactored. It is easier for contributors to implement new features.
-7. BREAKING CHANGES: `--station` -> `--search`, `--discover-by-country` -> `--country`, `--discover-by-tag` -> `--tag`, `--discover-by-state` -> `--state`, `--discover-by-language` -> `--lamguage`, `--add-station` -> `--add`, `--add-to-favorite` -> `--favorite`, `--show-favorite-list` -> `--list`
+7. BREAKING CHANGES: `--station` -> `--search`, `--discover-by-country` -> `--country`, `--discover-by-tag` -> `--tag`, `--discover-by-state` -> `--state`, `--discover-by-language` -> `--language`, `--add-station` -> `--add`, `--add-to-favorite` -> `--favorite`, `--show-favorite-list` -> `--list`
## 2.6.0
@@ -60,7 +71,7 @@
## 2.4.0
1. Crashes on Windows fixed
-Fixed setup-related issues (development purpose)
+2. Fixed setup-related issues (development purpose)
## 2.3.0
diff --git a/CONTRIBUTION.md b/CONTRIBUTION.md
new file mode 100644
index 0000000..9dd18e0
--- /dev/null
+++ b/CONTRIBUTION.md
@@ -0,0 +1,52 @@
+# Contribution Guide
+
+Welcome to the radio-active project! We're thrilled that you want to contribute. Before you get started, please take a moment to read this guide to understand our contribution process.
+
+
+## Getting Started
+
+To get started, make sure you have `git`, `ffmpeg` and `python3` installed on your local machine. You'll also need a GitHub account.
+
+## How to Contribute
+
+### Fork the Repository
+
+1. Click the "Fork" button on the top right of this repository's page.
+2. This will create a copy of the repository in your GitHub account.
+
+### Clone Your Fork
+
+1. Clone your fork to your local machine using the following command:
+ ```bash
+ git clone https://github.com/deep5050/radio-active.git
+ git checkout -b your-branch-name
+ ```
+
+### Install dependencies
+```bash
+pip3 install -r requirements.txt
+pip3 install -r requirements-dev.txt
+```
+
+### Make changes.
+
+Modify the code as required
+
+### Test Your Changes
+
+Before submitting your changes, please ensure that your code doesn't break the existing functionality.
+
+Run `make` to install it locally and test before you push changes!
+
+ ```
+ git add .
+ git commit -m "Add your commit message here" --signoff
+ git push
+ ```
+### Create a Pull Request
+Visit the original repository on GitHub.
+You should see a "New Pull Request" button. Click on it.
+Follow the instructions to create your pull request.
+
+Fill the description section with meaningful message.
+
diff --git a/Makefile b/Makefile
index d86ef1c..9f11434 100644
--- a/Makefile
+++ b/Makefile
@@ -6,7 +6,7 @@ SRC_DIR = "radioactive"
TEST_DIR = "test"
.PHONY: all clean isort check dist deploy test-deploy help build install install-dev test
-all: clean format check build install
+all: clean isort format check build install
check:
@echo "Chceking linting errors......."
diff --git a/README.md b/README.md
index ea47ec6..fe8ecf2 100644
--- a/README.md
+++ b/README.md
@@ -27,11 +27,14 @@
+
### Features
- [x] Supports more than 40K stations !! :radio:
+- [x] Record audio from live radio on demand :zap:
+- [x] Get song information on run-time 🎶
- [x] Saves last station information
-- [x] Favorite stations (Aliasing) :heart:
+- [x] Favorite stations :heart:
- [x] Selection menu for favorite stations
- [x] Supports user-added stations :wrench:
- [x] Looks minimal and user-friendly
@@ -39,18 +42,17 @@
- [x] Finds nearby stations
- [x] Discovers stations by genre
- [x] Discovers stations by language
-- [x] Record audio from live radio on demand :zap:
- [ ] I'm feeling lucky! Play Random stations
- [ ] VLC, MPV player support
-> See my progress ➡️ [here]([https://github.com/deep5050/radio-active/projects/1](https://github.com/users/deep5050/projects/5))
+> See my progress ➡️ [here](https://github.com/users/deep5050/projects/5)
### Why radioactive?
While there are various CLI-based radio players like [PyRadio](https://github.com/coderholic/pyradio) and [TERA](https://github.com/shinokada/tera), Radioactive stands out for its simplicity. It's designed to work seamlessly right from the start. You don't need to be a hardcore Linux or Vim expert to enjoy radio stations with Radioactive. The goal of Radioactive is to offer a straightforward user interface that's easy to grasp and comes preconfigured, without unnecessary complexities.
-### Showcase
+### In the Spotlight
The praise from YouTube channels and blogs underscores Radioactive's emergence as a top choice for radio enthusiasts. Its simple yet powerful features, make it a must-try application for radio lovers of all expertise levels. Discover the world of radio with ease – experience Radioactive today.
@@ -62,6 +64,7 @@ The praise from YouTube channels and blogs underscores Radioactive's emergence a
6. Awesome-stars: https://arbal.github.io/awesome-stars/#:~:text=deep5050/radio%2Dactive%20%2D%20Play%20any%20radios%20around%20the%20globe%20right%20from%20the%20terminal%20%3Azap%3A
7. OpenSourceAgenda: https://www.opensourceagenda.com/projects/my-awesome-stars#:~:text=deep5050/radio%2Dactive%20%2D%20Play%20any%20radios%20around%20the%20globe%20right%20from%20the%20terminal%20%3Azap%3A
+
### Install
Simply run: `pip3 install --upgrade radio-active`
@@ -111,39 +114,41 @@ Search a station with `radio --search [STATION_NAME]` or simply `radio` :zap: to
-
-
+
### Options
-| Argument | Note | Description | Default |
-| ------------------ | ----------------------------------- | ---------------------------------------------- | ------------- |
-| `--search`, `-S` | Required (Optional from second run) | Station name | None |
-| `--play`, `-P` | Optional | A station from fav list or url for direct play | None |
-| `--last` | Optional | Play last played station | False |
-| `--uuid`, `-U` | Optional | ID of the station | None |
-| `--loglevel` | Optional | Log level of the program | Info |
-| `--add` , `-A` | Optional | Add an entry to fav list | False |
-| `--list`, `-W` | Optional | Show fav list | False |
-| `--favorite`, `-F` | Optional | Add current station to fav list | False |
-| `--flush` | Optional | Remove all the entries from fav list | False |
-| `--country`, `-C` | Optional | Discover stations by country code | False |
-| `--state` | Optional | Discover stations by country state | False |
-| `--tag` | Optional | Discover stations by tags/genre | False |
-| `--language` | optional | Discover stations by | False |
-| `--limit` | Optional | Limit the # of results in the Discover table | 100 |
-| `--volume` , `-V` | Optional | Change the volume passed into ffplay | 80 |
-| `--kill` , `-K` | Optional | Kill background radios. | False |
-| `--record` , `-R` | Optional | Record a station and save to file | False |
-| `--filename`, `-N` | Optional | Filename to used to save the recorded audio | None |
-| `--filepath` | Optional | Path to save the recordings | |
-| `--filetype`, `-T` | Optional | Format of the recording (mp3/auto) | mp3 |
+| Argument | Note | Description | Default |
+| ------------------ | -------- | ---------------------------------------------- | ------------- |
+| `--search`, `-S` | Optional | Station name | None |
+| `--play`, `-P` | Optional | A station from fav list or url for direct play | None |
+| `--country`, `-C` | Optional | Discover stations by country code | False |
+| `--state` | Optional | Discover stations by country state | False |
+| `--language` | optional | Discover stations by | False |
+| `--tag` | Optional | Discover stations by tags/genre | False |
+| `--uuid`, `-U` | Optional | ID of the station | None |
+| `--record` , `-R` | Optional | Record a station and save to file | False |
+| `--filename`, `-N` | Optional | Filename to used to save the recorded audio | None |
+| `--filepath` | Optional | Path to save the recordings | |
+| `--filetype`, `-T` | Optional | Format of the recording (mp3/auto) | mp3 |
+| `--last` | Optional | Play last played station | False |
+| `--sort` | Optional | Sort the result page | name |
+| `--limit` | Optional | Limit the # of results in the Discover table | 100 |
+| `--volume` , `-V` | Optional | Change the volume passed into ffplay | 80 |
+| `--favorite`, `-F` | Optional | Add current station to fav list | False |
+| `--add` , `-A` | Optional | Add an entry to fav list | False |
+| `--list`, `-W` | Optional | Show fav list | False |
+| `--remove` | Optional | Remove entries from favorite list | False |
+| `--flush` | Optional | Remove all the entries from fav list | False |
+| `--kill` , `-K` | Optional | Kill background radios. | False |
+| `--loglevel` | Optional | Log level of the program | Info |
+> **NOTE:** Once you save/play at least one station, invoking `radio` without any options will show a selection menu
> `--search`, `-S`: Search for a station online.
@@ -172,13 +177,26 @@ Input a command during the radio playback to perform an action. Available comman
```
Enter a command to perform an action: ?
-q/Q/quit: Quit radioactive
-h/H/help/?: Show this help message
+t/T/track: Current song name (track info)
r/R/record: Record a station
f/F/fav: Add station to favorite list
rf/RF/recordfile: Specify a filename for the recording.
+h/H/help/?: Show this help message
+q/Q/quit: Quit radioactive
```
+### sort parameters
+
+you can sort the result page with these parameters:
+- `name` (default)
+- `votes` (based on user votes)
+- `codec`
+- `bitrate`
+- `lastcheckok` (active stations)
+- `lastchecktime` (recent active)
+- `clickcount` (total play count)
+- `clicktrend` (currently trending stations)
+- `random`
### Bonus Tips
@@ -230,6 +248,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
Joe Smith ⚠️ 💻 🤔 |
salehjafarli 💻 |
+ marvoh 💻 🐛 |
diff --git a/radioactive/__main__.py b/radioactive/__main__.py
index ced3a74..a5cc308 100755
--- a/radioactive/__main__.py
+++ b/radioactive/__main__.py
@@ -8,23 +8,29 @@
from radioactive.alias import Alias
from radioactive.app import App
-from radioactive.args import Parser
from radioactive.handler import Handler
from radioactive.help import show_help
from radioactive.last_station import Last_station
+from radioactive.parser import parse_options
from radioactive.player import Player, kill_background_ffplays
-from radioactive.utilities import (handle_add_station, handle_add_to_favorite,
- handle_current_play_panel,
- handle_direct_play, handle_favorite_table,
- handle_listen_keypress, handle_log_level,
- handle_play_last_station, handle_record,
- handle_save_last_station,
- handle_search_stations,
- handle_station_selection_menu,
- handle_station_uuid_play,
- handle_update_screen,
- handle_user_choice_from_search_result,
- handle_welcome_screen)
+from radioactive.utilities import (
+ check_sort_by_parameter,
+ handle_add_station,
+ handle_add_to_favorite,
+ handle_current_play_panel,
+ handle_direct_play,
+ handle_favorite_table,
+ handle_listen_keypress,
+ handle_play_last_station,
+ handle_record,
+ handle_save_last_station,
+ handle_search_stations,
+ handle_station_selection_menu,
+ handle_station_uuid_play,
+ handle_update_screen,
+ handle_user_choice_from_search_result,
+ handle_welcome_screen,
+)
# globally needed as signal handler needs it
# to terminate main() properly
@@ -78,42 +84,12 @@ def final_step(options, last_station, alias, handler):
def main():
log.level("info")
- parser = Parser()
- app = App()
- args = parser.parse()
-
- options = {}
- # ----------------- all the args ------------- #
- options["show_help_table"] = args.help
- options["search_station_name"] = args.search_station_name
- options["direct_play"] = args.direct_play
- options["play_last_station"] = args.play_last_station
-
- options["search_station_uuid"] = args.search_station_uuid
-
- options["discover_country_code"] = args.discover_country_code
- options["discover_state"] = args.discover_state
- options["discover_language"] = args.discover_language
- options["discover_tag"] = args.discover_tag
- limit = args.limit
- options["limit"] = int(limit) if limit else 100
- log.debug("limit is set to: {}".format(limit))
-
- options["add_station"] = args.new_station
- options["add_to_favorite"] = args.add_to_favorite
- options["show_favorite_list"] = args.show_favorite_list
-
- options["flush_fav_list"] = args.flush
- options["kill_ffplays"] = args.kill_ffplays
+ app = App()
- options["record_stream"] = args.record_stream
- options["record_file"] = args.record_file
- options["record_file_format"] = args.record_file_format
- options["record_file_path"] = args.record_file_path
+ options = parse_options()
- options["target_url"] = ""
- options["volume"] = args.volume
+ handle_welcome_screen()
VERSION = app.get_version()
@@ -123,9 +99,8 @@ def main():
last_station = Last_station()
# --------------- app logic starts here ------------------- #
- handle_welcome_screen()
- if args.version:
+ if options["version"]:
log.info("RADIO-ACTIVE : version {}".format(VERSION))
sys.exit(0)
@@ -133,8 +108,6 @@ def main():
show_help()
sys.exit(0)
- options["loglevel"] = handle_log_level(args)
-
if options["flush_fav_list"]:
sys.exit(alias.flush())
@@ -149,12 +122,19 @@ def main():
if options["add_station"]:
handle_add_station(alias)
+ if options["remove_fav_stations"]:
+ # handle_remove_stations(alias)
+ alias.remove_entries()
+ sys.exit(0)
+
+ options["sort_by"] = check_sort_by_parameter(options["sort_by"])
+
handle_update_screen(app)
# ----------- country ----------- #
if options["discover_country_code"]:
response = handler.discover_by_country(
- options["discover_country_code"], options["limit"]
+ options["discover_country_code"], options["limit"], options["sort_by"]
)
if response is not None:
(
@@ -168,7 +148,7 @@ def main():
# -------------- state ------------- #
if options["discover_state"]:
response = handler.discover_by_state(
- options["discover_state"], options["limit"]
+ options["discover_state"], options["limit"], options["sort_by"]
)
if response is not None:
(
@@ -182,7 +162,7 @@ def main():
# ----------- language ------------ #
if options["discover_language"]:
response = handler.discover_by_language(
- options["discover_language"], options["limit"]
+ options["discover_language"], options["limit"], options["sort_by"]
)
if response is not None:
(
@@ -195,7 +175,9 @@ def main():
# -------------- tag ------------- #
if options["discover_tag"]:
- response = handler.discover_by_tag(options["discover_tag"], options["limit"])
+ response = handler.discover_by_tag(
+ options["discover_tag"], options["limit"], options["sort_by"]
+ )
if response is not None:
(
options["curr_station_name"],
@@ -235,7 +217,10 @@ def main():
):
response = [{}]
response = handle_search_stations(
- handler, options["search_station_name"], options["limit"]
+ handler,
+ options["search_station_name"],
+ options["limit"],
+ options["sort_by"],
)
if response is not None:
(
diff --git a/radioactive/alias.py b/radioactive/alias.py
index 1059efe..a6a63fd 100644
--- a/radioactive/alias.py
+++ b/radioactive/alias.py
@@ -1,5 +1,6 @@
import os.path
+from pick import pick
from zenlog import log
@@ -10,9 +11,23 @@ def __init__(self):
self.alias_path = os.path.join(os.path.expanduser("~"), ".radio-active-alias")
+ def write_stations(self, station_map):
+ """Write stations file from generated map"""
+ with open(self.alias_path, "w") as f:
+ f.flush()
+ for entry in station_map:
+ f.write(
+ "{}=={}\n".format(
+ entry["name"].strip(), entry["uuid_or_url"].strip()
+ )
+ )
+ return True
+
def generate_map(self):
"""parses the fav list file and generates a list"""
# create alias map
+ self.alias_map = []
+
if os.path.exists(self.alias_path):
log.debug(f"Alias file at: {self.alias_path}")
try:
@@ -81,3 +96,35 @@ def flush(self):
log.debug("Error: {}".format(e))
log.error("could not delete your favorite list. something went wrong")
return 1
+
+ def remove_entries(self):
+ # select entries from fav menu and remove them
+ self.generate_map()
+
+ if not self.alias_map:
+ log.error("No stations to be removed!")
+ return
+
+ title = "Select stations to be removed. Hit 'SPACE' to select "
+ options = [entry["name"] for entry in self.alias_map]
+ selected = pick(
+ options, title, indicator="->", multiselect=True, min_selection_count=1
+ )
+
+ # Extract integer numbers and create a new list
+ indices_to_remove = [item[1] for item in selected if isinstance(item[1], int)]
+
+ # remove selected entries from the map, and regenerate
+ filtered_list = [
+ self.alias_map[i]
+ for i in range(len(self.alias_map))
+ if i not in indices_to_remove
+ ]
+
+ log.debug(
+ f"Current # of entries reduced to : {len(filtered_list)} from {len(self.alias_map)}"
+ )
+
+ self.write_stations(filtered_list)
+ self.alias_map = filtered_list
+ log.info("Stations removed successfully!")
diff --git a/radioactive/app.py b/radioactive/app.py
index badad9c..736a0de 100644
--- a/radioactive/app.py
+++ b/radioactive/app.py
@@ -9,7 +9,7 @@
class App:
def __init__(self):
- self.__VERSION__ = "2.8.0" # change this on every update #
+ self.__VERSION__ = "2.9.0" # change this on every update #
self.pypi_api = "https://pypi.org/pypi/radio-active/json"
self.remote_version = ""
diff --git a/radioactive/args.py b/radioactive/args.py
index 65f390c..f9af9a9 100644
--- a/radioactive/args.py
+++ b/radioactive/args.py
@@ -37,6 +37,7 @@ def __init__(self):
dest="search_station_name",
help="Specify a station name",
)
+
self.parser.add_argument(
"--play",
"-P",
@@ -106,6 +107,14 @@ def __init__(self):
help="Limit of entries in discover table",
)
+ self.parser.add_argument(
+ "--sort",
+ action="store",
+ dest="stations_sort_by",
+ default="name",
+ help="Sort stations",
+ )
+
self.parser.add_argument(
"--add",
"-A",
@@ -131,6 +140,14 @@ def __init__(self):
help="Show your favorite list in table format",
)
+ self.parser.add_argument(
+ "--remove",
+ action="store_true",
+ default=False,
+ dest="remove_fav_stations",
+ help="Remove stations from favorite list",
+ )
+
self.parser.add_argument(
"--flush",
action="store_true",
diff --git a/radioactive/handler.py b/radioactive/handler.py
index e78ed17..85b6599 100644
--- a/radioactive/handler.py
+++ b/radioactive/handler.py
@@ -16,12 +16,90 @@
def trim_string(text, max_length=40):
+ """
+ Trim a string to a maximum length and add ellipsis if needed.
+
+ Args:
+ text (str): The input text to be trimmed.
+ max_length (int, optional): The maximum length of the trimmed string. Defaults to 40.
+
+ Returns:
+ str: The trimmed string, possibly with an ellipsis (...) if it was shortened.
+ """
if len(text) > max_length:
return text[:max_length] + "..."
else:
return text
+def print_table(response, columns, sort_by="name"):
+ """
+ Print the table applying the sort logic.
+
+ Args:
+ response (list): A list of data to be displayed in the table.
+ columns (list): List of column specifications in the format "col_name:response_key@max_str".
+ sort_by (str): The column by which to sort the table.
+
+ Returns:
+ list: The original response data.
+ """
+
+ if not response:
+ log.error("No stations found")
+ sys.exit(1)
+
+ if len(response) >= 1:
+ table = Table(
+ show_header=True,
+ header_style="magenta",
+ expand=True,
+ min_width=85,
+ safe_box=True,
+ # show_footer=True,
+ # show_lines=True,
+ # padding=0.1,
+ # collapse_padding=True,
+ )
+ table.add_column("ID", justify="center")
+
+ for col_spec in columns:
+ col_name, response_key, max_str = (
+ col_spec.split(":")[0],
+ col_spec.split(":")[1].split("@")[0],
+ int(col_spec.split("@")[1]),
+ )
+ table.add_column(col_name, justify="left")
+
+ # do not need extra columns for these cases
+ if sort_by not in ["name", "random"]:
+ table.add_column(sort_by, justify="left")
+
+ for i, station in enumerate(response):
+ row_data = [str(i + 1)] # for ID
+
+ for col_spec in columns:
+ col_name, response_key, max_str = (
+ col_spec.split(":")[0],
+ col_spec.split(":")[1].split("@")[0],
+ int(col_spec.split("@")[1]),
+ )
+ row_data.append(
+ trim_string(station.get(response_key, ""), max_length=max_str)
+ )
+
+ if sort_by not in ["name", "random"]:
+ row_data.append(str(station.get(sort_by, "")))
+
+ table.add_row(*row_data)
+
+ console.print(table)
+ # log.info(
+ # "If the table does not fit into your screen, \ntry to maximize the window, decrease the font by a bit, and retry"
+ # )
+ return response
+
+
class Handler:
"""
radio-browser API handler. This module communicates with the underlying API via PyRadios
@@ -51,61 +129,34 @@ def get_country_code(self, name):
return country["iso_3166_1"]
return None
- def station_validator(self):
- """Validates a response from the API and takes appropriate decision"""
-
- # when no response from the API
- if not self.response:
- log.error("No stations found by the name")
- return []
-
- # when multiple results found
- if len(self.response) > 1:
- table = Table(show_header=True, header_style="bold magenta")
- table.add_column("ID", justify="center")
- table.add_column("Station", justify="left")
- # table.add_column("UUID", justify="center")
- table.add_column("Country", justify="center")
- table.add_column("Tags", justify="center")
-
- log.warn("showing {} stations with the name!".format(len(self.response)))
-
- for i in range(0, len(self.response)):
- station = self.response[i]
- table.add_row(
- str(i + 1),
- trim_string(station["name"], max_length=50),
- # station["stationuuid"],
- station["countrycode"],
- trim_string(
- station["tags"]
- ), # trimming tags to make the table shorter
- )
-
- console.print(table)
- log.info(
- "If the table does not fit into your screen, \
- \ntry to maximize the window , decrease the font by a bit and retry"
- )
- return self.response
-
- # when exactly one response found
+ def validate_uuid_station(self):
if len(self.response) == 1:
- log.info("Station found: {}".format(self.response[0]["name"].strip()))
log.debug(json.dumps(self.response[0], indent=3))
self.target_station = self.response[0]
+
# register a valid click to increase its popularity
self.API.click_counter(self.target_station["stationuuid"])
return self.response
- # return self.response[0]["name"].strip()
# ---------------------------- NAME -------------------------------- #
- def search_by_station_name(self, _name=None, limit=100):
+ def search_by_station_name(self, _name=None, limit=100, sort_by: str = "name"):
"""search and play a station by its name"""
+ reversed = sort_by != "name"
+
try:
- self.response = self.API.search(name=_name, name_exact=False, limit=limit)
- return self.station_validator()
+ response = self.API.search(
+ name=_name,
+ name_exact=False,
+ limit=limit,
+ order=str(sort_by),
+ reverse=reversed,
+ )
+ return print_table(
+ response,
+ ["Station:name@30", "Country:country@20", "Tags:tags@20"],
+ sort_by=sort_by,
+ )
except Exception as e:
log.debug("Error: {}".format(e))
log.error("Something went wrong. please try again.")
@@ -116,21 +167,27 @@ def play_by_station_uuid(self, _uuid):
"""search and play station by its stationuuid"""
try:
self.response = self.API.station_by_uuid(_uuid)
- return self.station_validator() # should return a station name also
+ return self.validate_uuid_station()
except Exception as e:
log.debug("Error: {}".format(e))
log.error("Something went wrong. please try again.")
sys.exit(1)
# -------------------------- COUNTRY ----------------------#
- def discover_by_country(self, country_code_or_name, limit):
+ def discover_by_country(self, country_code_or_name, limit, sort_by: str = "name"):
+ # set reverse to false if name is is the parameter for sorting
+ reversed = sort_by != "name"
+
# check if it is a code or name
if len(country_code_or_name.strip()) == 2:
# it's a code
- log.debug("Country code {} provided".format(country_code_or_name))
+ log.debug("Country code '{}' provided".format(country_code_or_name))
try:
response = self.API.search(
- countrycode=country_code_or_name, limit=limit
+ countrycode=country_code_or_name,
+ limit=limit,
+ order=str(sort_by),
+ reverse=reversed,
)
except Exception as e:
log.debug("Error: {}".format(e))
@@ -138,12 +195,16 @@ def discover_by_country(self, country_code_or_name, limit):
sys.exit(1)
else:
# it's name
- log.debug("Country name {} provided".format(country_code_or_name))
+ log.debug("Country name '{}' provided".format(country_code_or_name))
code = self.get_country_code(country_code_or_name)
if code:
try:
response = self.API.search(
- countrycode=code, limit=limit, country_exact=True
+ countrycode=code,
+ limit=limit,
+ country_exact=True,
+ order=str(sort_by),
+ reverse=reversed,
)
except Exception as e:
log.debug("Error: {}".format(e))
@@ -153,150 +214,94 @@ def discover_by_country(self, country_code_or_name, limit):
log.error("Not a valid country name")
sys.exit(1)
- if len(response) > 1:
- log.info("Result for country: {}".format(response[0]["country"]))
- table = Table(show_header=True, header_style="bold magenta")
- table.add_column("ID", justify="center")
- table.add_column("Station", justify="left")
- # table.add_column("UUID", justify="center")
- table.add_column("State", justify="center")
- table.add_column("Tags", justify="center")
- table.add_column("Language", justify="center")
-
- for i in range(0, len(response)):
- current_response = response[i]
- table.add_row(
- str(i + 1),
- trim_string(current_response["name"], max_length=30),
- # res["stationuuid"],
- current_response["state"],
- trim_string(current_response["tags"], max_length=20),
- trim_string(current_response["language"], max_length=20),
- )
- console.print(table)
- log.info(
- "If the table does not fit into your screen,\
- \ntry to maximize the window , decrease the font by a bit and retry"
- )
-
- return response
- else:
- log.error("No stations found for the country code/name, recheck it")
- sys.exit(1)
+ # display the result
+ print_table(
+ response,
+ [
+ "Station:name@30",
+ "State:state@20",
+ "Tags:tags@20",
+ "Language:language@20",
+ ],
+ sort_by=sort_by,
+ )
+ return response
# ------------------- by state ---------------------
- def discover_by_state(self, state, limit):
+ def discover_by_state(self, state, limit, sort_by: str = "name"):
+ reversed = sort_by != "name"
+
try:
- discover_result = self.API.search(state=state, limit=limit)
+ response = self.API.search(
+ state=state, limit=limit, order=str(sort_by), reverse=reversed
+ )
except Exception:
log.error("Something went wrong. please try again.")
sys.exit(1)
- if len(discover_result) > 1:
- table = Table(show_header=True, header_style="bold magenta")
- table.add_column("ID", justify="center")
- table.add_column("Station", justify="left")
- # table.add_column("UUID", justify="center")
- table.add_column("Country", justify="center")
- table.add_column("Tags", justify="center")
- table.add_column("Language", justify="center")
-
- for i in range(0, len(discover_result)):
- res = discover_result[i]
- table.add_row(
- str(i + 1),
- trim_string(res["name"], max_length=30),
- # res["stationuuid"],
- trim_string(res["country"], max_length=20),
- trim_string(res["tags"], max_length=20),
- trim_string(res["language"], max_length=20),
- )
- console.print(table)
- log.info(
- "If the table does not fit into your screen, \ntry to maximize the window , decrease the font by a bit and retry"
- )
-
- return discover_result
- else:
- log.error("No stations found for the state, recheck it")
- sys.exit(1)
+ return print_table(
+ response,
+ [
+ "Station:name@30",
+ "Country:country@20",
+ "State:state@20",
+ "Tags:tags@20",
+ "Language:language@20",
+ ],
+ sort_by=sort_by,
+ )
# -----------------by language --------------------
- def discover_by_language(self, language, limit):
+ def discover_by_language(self, language, limit, sort_by: str = "name"):
+ reversed = sort_by != "name"
+
try:
- discover_result = self.API.search(language=language, limit=limit)
+ response = self.API.search(
+ language=language, limit=limit, order=str(sort_by), reverse=reversed
+ )
except Exception as e:
log.debug("Error: {}".format(e))
log.error("Something went wrong. please try again.")
sys.exit(1)
- if len(discover_result) > 1:
- table = Table(show_header=True, header_style="bold magenta")
- table.add_column("ID", justify="center")
- table.add_column("Station", justify="left")
- # table.add_column("UUID", justify="center")
- table.add_column("Country", justify="center")
- table.add_column("Tags", justify="center")
-
- for i in range(0, len(discover_result)):
- res = discover_result[i]
- table.add_row(
- str(i + 1),
- trim_string(res["name"], max_length=30),
- # res["stationuuid"],
- trim_string(res["country"], max_length=20),
- trim_string(res["tags"], max_length=30),
- )
- console.print(table)
- log.info(
- "If the table does not fit into your screen, \ntry to maximize the window, decrease the font by a bit and retry"
- )
-
- return discover_result
- else:
- log.error("No stations found for the language, recheck it")
- sys.exit(1)
+ return print_table(
+ response,
+ [
+ "Station:name@30",
+ "Country:country@20",
+ "Language:language@20",
+ "Tags:tags@20",
+ ],
+ sort_by,
+ )
# -------------------- by tag ---------------------- #
+ def discover_by_tag(self, tag, limit, sort_by: str = "name"):
+ reversed = sort_by != "name"
- def discover_by_tag(self, tag, limit):
try:
- discover_result = self.API.search(tag=tag, limit=limit)
+ response = self.API.search(
+ tag=tag, limit=limit, order=str(sort_by), reverse=reversed
+ )
except Exception as e:
log.debug("Error: {}".format(e))
log.error("Something went wrong. please try again.")
sys.exit(1)
- if len(discover_result) > 1:
- table = Table(show_header=True, header_style="bold magenta")
- table.add_column("ID", justify="center")
- table.add_column("Station", justify="left")
- # table.add_column("UUID", justify="center")
- table.add_column("country", justify="center")
- table.add_column("Language", justify="center")
-
- for i in range(0, len(discover_result)):
- res = discover_result[i]
- table.add_row(
- str(i + 1),
- trim_string(res["name"], max_length=30),
- # res["stationuuid"],
- trim_string(res["country"], max_length=20),
- trim_string(res["language"], max_length=20),
- )
- console.print(table)
- log.info(
- "If the table does not fit into your screen, \
- \ntry to maximize the window , decrease the font by a bit and retry"
- )
- return discover_result
- else:
- log.error("No stations found for the tag, recheck it")
- sys.exit(1)
-
- # ---- increase click count ------------- #
+ return print_table(
+ response,
+ [
+ "Station:name@30",
+ "Country:country@20",
+ "Language:language@20",
+ "Tags:tags@50",
+ ],
+ sort_by,
+ )
+
+ # ---- Increase click count ------------- #
def vote_for_uuid(self, UUID):
try:
result = self.API.click_counter(UUID)
diff --git a/radioactive/help.py b/radioactive/help.py
index a556658..ac48b8f 100644
--- a/radioactive/help.py
+++ b/radioactive/help.py
@@ -20,31 +20,54 @@ def show_help():
"A station name to search on the internet",
"",
)
+
table.add_row(
- "--play , -P",
- "A station name from fav list or a stream url",
+ "--uuid , -U",
+ "A station UUID to play it directly",
"",
)
+
table.add_row(
- "--last",
- "Play last played station",
- "False",
+ "--country, -C",
+ "Discover stations by country code",
+ "",
)
table.add_row(
- "--uuid , -U",
- "A station UUID to play it directly",
+ "--state",
+ "Discover stations by country state",
"",
)
+
table.add_row(
- "--loglevel",
- "Log level of the program: info,warning,error,debug",
- "info",
+ "--tag",
+ "Discover stations by tags/genre",
+ "",
+ )
+
+ table.add_row(
+ "--language",
+ "Discover stations by language",
+ "",
+ )
+
+ table.add_row(
+ "--play , -P",
+ "A station name from fav list or a stream url",
+ "",
)
+
+ table.add_row(
+ "--last",
+ "Play last played station",
+ "False",
+ )
+
table.add_row(
"--add , -A",
"Add a station to your favorite list",
"False",
)
+
table.add_row(
"--favorite, -F ",
"Add current station to favorite list",
@@ -58,27 +81,15 @@ def show_help():
)
table.add_row(
- "--country, -C",
- "Discover stations by country code",
- "",
- )
-
- table.add_row(
- "--state",
- "Discover stations by country state",
- "",
- )
-
- table.add_row(
- "--tag",
- "Discover stations by tags/genre",
- "",
+ "--remove",
+ "Remove stations from favorite list",
+ "False",
)
table.add_row(
- "--language",
- "Discover stations by language",
- "",
+ "--flush",
+ "Clear your favorite list",
+ "False",
)
table.add_row(
@@ -87,17 +98,18 @@ def show_help():
"100",
)
+ table.add_row(
+ "--sort",
+ "Sort the results page, see documentation",
+ "clickcount",
+ )
+
table.add_row(
"--volume, -V",
"Volume of the radio between 0 and 100",
"80",
)
- table.add_row(
- "--flush",
- "Clear your favorite list",
- "False",
- )
table.add_row(
"--record, -R",
"Record current stations audio",
@@ -127,6 +139,12 @@ def show_help():
"False",
)
+ table.add_row(
+ "--loglevel",
+ "Log level of the program: info,warning,error,debug",
+ "info",
+ )
+
console.print(table)
print(
"For more details : https://github.com/deep5050/radio-active/blob/main/README.md"
diff --git a/radioactive/parser.py b/radioactive/parser.py
new file mode 100644
index 0000000..00a19de
--- /dev/null
+++ b/radioactive/parser.py
@@ -0,0 +1,57 @@
+from zenlog import log
+
+from radioactive.args import Parser
+
+
+def parse_options():
+ parser = Parser()
+ args = parser.parse()
+ options = {}
+ # ----------------- all the args ------------- #
+ options["version"] = args.version
+ options["show_help_table"] = args.help
+ options["loglevel"] = args.log_level
+
+ # check log levels
+ if options["loglevel"] in ["info", "error", "warning", "debug"]:
+ log.level(options["loglevel"])
+ else:
+ log.level("info")
+ log.warning("Correct log levels are: error,warning,info(default),debug")
+
+ # check is limit is a valid integer
+ limit = args.limit
+ options["limit"] = int(limit) if limit else 100
+ log.debug("limit is set to: {}".format(limit))
+
+ options["search_station_name"] = args.search_station_name
+ options["search_station_uuid"] = args.search_station_uuid
+
+ options["play_last_station"] = args.play_last_station
+ options["direct_play"] = args.direct_play
+
+ options["sort_by"] = args.stations_sort_by
+
+ options["discover_country_code"] = args.discover_country_code
+ options["discover_state"] = args.discover_state
+ options["discover_language"] = args.discover_language
+ options["discover_tag"] = args.discover_tag
+
+ options["add_station"] = args.new_station
+
+ options["show_favorite_list"] = args.show_favorite_list
+ options["add_to_favorite"] = args.add_to_favorite
+ options["flush_fav_list"] = args.flush
+ options["remove_fav_stations"] = args.remove_fav_stations
+
+ options["kill_ffplays"] = args.kill_ffplays
+
+ options["record_stream"] = args.record_stream
+ options["record_file"] = args.record_file
+ options["record_file_format"] = args.record_file_format
+ options["record_file_path"] = args.record_file_path
+
+ options["target_url"] = ""
+ options["volume"] = args.volume
+
+ return options
diff --git a/radioactive/utilities.py b/radioactive/utilities.py
index dca70af..8bd3e9b 100644
--- a/radioactive/utilities.py
+++ b/radioactive/utilities.py
@@ -1,9 +1,13 @@
"""Handler functions for __main__.py"""
import datetime
+import json
import os
+import subprocess
import sys
+from random import randint
+import requests
from pick import pick
from rich import print
from rich.console import Console
@@ -19,14 +23,41 @@
RED_COLOR = "\033[91m"
END_COLOR = "\033[0m"
+global_current_station_info = {}
+
+
+def handle_fetch_song_title(url):
+ """Fetch currently playing track information"""
+ log.info("Fetching the current track info")
+ log.debug("Attempting to retrieve track info from: {}".format(url))
+ # Run ffprobe command and capture the metadata
+ cmd = [
+ "ffprobe",
+ "-v",
+ "quiet",
+ "-print_format",
+ "json",
+ "-show_format",
+ "-show_entries",
+ "format=icy",
+ url,
+ ]
+ track_name = ""
-def handle_log_level(args):
- log_level = args.log_level
- if log_level in ["info", "error", "warning", "debug"]:
- log.level(log_level)
- return args.log_level
+ try:
+ output = subprocess.check_output(cmd).decode("utf-8")
+ data = json.loads(output)
+ log.debug(f"station info: {data}")
+
+ # Extract the station name (icy-name) if available
+ track_name = data.get("format", {}).get("tags", {}).get("StreamTitle", "")
+ except:
+ log.error("Error while fetching the track name")
+
+ if track_name != "":
+ log.info(f"🎶: {track_name}")
else:
- log.warning("Correct log levels are: error,warning,info(default),debug")
+ log.error("No track information available")
def handle_record(
@@ -110,6 +141,8 @@ def handle_welcome_screen():
""",
title="[b]RADIOACTIVE[/b]",
width=85,
+ expand=True,
+ safe_box=True,
)
print(welcome)
@@ -131,8 +164,14 @@ def handle_update_screen(app):
def handle_favorite_table(alias):
- log.info("Your favorite station list is below")
- table = Table(show_header=True, header_style="bold magenta")
+ # log.info("Your favorite station list is below")
+ table = Table(
+ show_header=True,
+ header_style="bold magenta",
+ min_width=85,
+ safe_box=False,
+ expand=True,
+ )
table.add_column("Station", justify="left")
table.add_column("URL / UUID", justify="left")
if len(alias.alias_map) > 0:
@@ -144,9 +183,34 @@ def handle_favorite_table(alias):
log.info("You have no favorite station list")
+def handle_show_station_info():
+ """Show important information regarding the current station"""
+ global global_current_station_info
+ custom_info = {}
+ try:
+ custom_info["name"] = global_current_station_info["name"]
+ custom_info["uuid"] = global_current_station_info["stationuuid"]
+ custom_info["url"] = global_current_station_info["url"]
+ custom_info["website"] = global_current_station_info["homepage"]
+ custom_info["country"] = global_current_station_info["country"]
+ custom_info["language"] = global_current_station_info["language"]
+ custom_info["tags"] = global_current_station_info["tags"]
+ custom_info["codec"] = global_current_station_info["codec"]
+ custom_info["bitrate"] = global_current_station_info["bitrate"]
+ print(custom_info)
+ except:
+ log.error("No station information available")
+
+
def handle_add_station(alias):
- left = input("Enter station name:")
- right = input("Enter station stream-url or radio-browser uuid:")
+ try:
+ left = input("Enter station name:")
+ right = input("Enter station stream-url or radio-browser uuid:")
+ except EOFError:
+ print()
+ log.debug("Ctrl+D (EOF) detected. Exiting gracefully.")
+ sys.exit(0)
+
if left.strip() == "" or right.strip() == "":
log.error("Empty inputs not allowed")
sys.exit(1)
@@ -159,7 +223,13 @@ def handle_add_to_favorite(alias, station_name, station_uuid_url):
try:
response = alias.add_entry(station_name, station_uuid_url)
if not response:
- user_input = input("Enter a different name: ")
+ try:
+ user_input = input("Enter a different name: ")
+ except EOFError:
+ print()
+ log.debug("Ctrl+D (EOF) detected. Exiting gracefully.")
+ sys.exit(0)
+
if user_input.strip() != "":
response = alias.add_entry(user_input.strip(), station_uuid_url)
except Exception as e:
@@ -186,10 +256,33 @@ def handle_station_uuid_play(handler, station_uuid):
return station_name, station_url
-def handle_search_stations(handler, station_name, limit):
+def check_sort_by_parameter(sort_by):
+ accepted_parameters = [
+ "name",
+ "votes",
+ "codec",
+ "bitrate",
+ "lastcheckok",
+ "lastchecktime",
+ "clickcount",
+ "clicktrend",
+ "random",
+ ]
+
+ if sort_by not in accepted_parameters:
+ log.warning("Sort parameter is unknown. Falling back to 'name'")
+
+ log.warning(
+ "choose from: name,votes,codec,bitrate,lastcheckok,lastchecktime,clickcount,clicktrend,random"
+ )
+ return "name"
+ return sort_by
+
+
+def handle_search_stations(handler, station_name, limit, sort_by):
log.debug("Searching API for: {}".format(station_name))
- return handler.search_by_station_name(station_name, limit)
+ return handler.search_by_station_name(station_name, limit, sort_by)
def handle_station_selection_menu(handler, last_station, alias):
@@ -203,7 +296,7 @@ def handle_station_selection_menu(handler, last_station, alias):
# no last station??
pass
- log.info("You can search for a station on internet using the --search option")
+ # log.info("You can search for a station on internet using the --search option")
title = "Please select a station from your favorite list:"
station_selection_names = []
station_selection_urls = []
@@ -271,8 +364,15 @@ def handle_listen_keypress(
):
log.info("Press '?' to see available commands\n")
while True:
- user_input = input("Enter a command to perform an action: ")
- if user_input == "r" or user_input == "R" or user_input == "record":
+ try:
+ user_input = input("Enter a command to perform an action: ")
+ except EOFError:
+ print()
+ log.debug("Ctrl+D (EOF) detected. Exiting gracefully.")
+ kill_background_ffplays()
+ sys.exit(0)
+
+ if user_input in ["r", "R", "record"]:
handle_record(
target_url,
station_name,
@@ -281,11 +381,17 @@ def handle_listen_keypress(
record_file_format,
loglevel,
)
- elif user_input == "rf" or user_input == "RF" or user_input == "recordfile":
+ elif user_input in ["rf", "RF", "recordfile"]:
# if no filename is provided try to auto detect
# else if ".mp3" is provided, use libmp3lame to force write to mp3
+ try:
+ user_input = input("Enter output filename: ")
+ except EOFError:
+ print()
+ log.debug("Ctrl+D (EOF) detected. Exiting gracefully.")
+ kill_background_ffplays()
+ sys.exit(0)
- user_input = input("Enter output filename: ")
# try to get extension from filename
try:
file_name, file_ext = user_input.split(".")
@@ -310,29 +416,29 @@ def handle_listen_keypress(
record_file_format,
loglevel,
)
+ elif user_input in ["i", "I", "info"]:
+ handle_show_station_info()
- elif user_input == "f" or user_input == "F" or user_input == "fav":
+ elif user_input in ["f", "F", "fav"]:
handle_add_to_favorite(alias, station_name, station_url)
- elif user_input == "q" or user_input == "Q" or user_input == "quit":
+ elif user_input in ["q", "Q", "quit"]:
kill_background_ffplays()
sys.exit(0)
- elif user_input == "w" or user_input == "W" or user_input == "list":
+ elif user_input in ["w", "W", "list"]:
alias.generate_map()
handle_favorite_table(alias)
+ elif user_input in ["t", "T", "track"]:
+ handle_fetch_song_title(target_url)
- elif (
- user_input == "h"
- or user_input == "H"
- or user_input == "?"
- or user_input == "help"
- ):
- log.info("h/help/?: Show this help message")
- log.info("q/quit: Quit radioactive")
+ elif user_input in ["h", "H", "?", "help"]:
+ log.info("t/track: Current track info")
+ log.info("i/info: Station information")
log.info("r/record: Record a station")
- log.info("f/fav: Add station to favorite list")
log.info("rf/recordfile: Specify a filename for the recording")
- # TODO: u for uuid, link for url, p for setting path
+ log.info("f/fav: Add station to favorite list")
+ log.info("h/help/?: Show this help message")
+ log.info("q/quit: Quit radioactive")
def handle_current_play_panel(curr_station_name=""):
@@ -344,6 +450,8 @@ def handle_current_play_panel(curr_station_name=""):
def handle_user_choice_from_search_result(handler, response):
+ global global_current_station_info
+
if not response:
log.debug("No result found!")
sys.exit(0)
@@ -351,9 +459,16 @@ def handle_user_choice_from_search_result(handler, response):
# single station found
log.debug("Exactly one result found")
- user_input = input("Want to play this station? Y/N: ")
+ try:
+ user_input = input("Want to play this station? Y/N: ")
+ except EOFError:
+ print()
+ sys.exit(0)
+
if user_input == ("y" or "Y"):
log.debug("Playing UUID from single response")
+ global_current_station_info = response[0]
+
return handle_station_uuid_play(handler, response[0]["stationuuid"])
else:
log.debug("Quitting")
@@ -362,12 +477,30 @@ def handle_user_choice_from_search_result(handler, response):
# multiple station
log.debug("Asking for user input")
- user_input = input("Type the result ID to play: ")
try:
+ log.info("Type 'r' to play a random station")
+ user_input = input("Type the result ID to play: ")
+ except EOFError:
+ print()
+ log.info("Exiting")
+ log.debug("EOF reached, quitting")
+ sys.exit(0)
+
+ try:
+ if user_input in ["r", "R", "random"]:
+ # pick a random integer withing range
+ user_input = randint(1, len(response) - 1)
+ log.debug(f"Radom station id: {user_input}")
+
user_input = int(user_input) - 1 # because ID starts from 1
if user_input in range(0, len(response)):
target_response = response[user_input]
log.debug("Selected: {}".format(target_response))
+ # log.info("UUID: {}".format(target_response["stationuuid"]))
+
+ # saving global info
+ global_current_station_info = target_response
+
return handle_station_uuid_play(handler, target_response["stationuuid"])
else:
log.error("Please enter an ID within the range")
@@ -379,11 +512,14 @@ def handle_user_choice_from_search_result(handler, response):
def handle_direct_play(alias, station_name_or_url=""):
"""Play a station directly with UUID or direct stream URL"""
- if "http" in station_name_or_url.strip():
+ if "://" in station_name_or_url.strip():
log.debug("Direct play: URL provided")
# stream URL
# call using URL with no station name N/A
- return "N/A", station_name_or_url
+ # let's attempt to get station name from url headers
+ # station_name = handle_station_name_from_headers(station_name_or_url)
+ station_name = handle_get_station_name_from_metadata(station_name_or_url)
+ return station_name, station_name_or_url
else:
log.debug("Direct play: station name provided")
# station name from fav list
@@ -401,3 +537,65 @@ def handle_direct_play(alias, station_name_or_url=""):
def handle_play_last_station(last_station):
station_obj = last_station.get_info()
return station_obj["name"], station_obj["uuid_or_url"]
+
+
+# uses ffprobe to fetch station name
+def handle_get_station_name_from_metadata(url):
+ """Get ICY metadata from ffprobe"""
+ log.info("Fetching the station name")
+ log.debug("Attempting to retrieve station name from: {}".format(url))
+ # Run ffprobe command and capture the metadata
+ cmd = [
+ "ffprobe",
+ "-v",
+ "quiet",
+ "-print_format",
+ "json",
+ "-show_format",
+ "-show_entries",
+ "format=icy",
+ url,
+ ]
+ station_name = "Unknown Station"
+
+ try:
+ output = subprocess.check_output(cmd).decode("utf-8")
+ data = json.loads(output)
+ log.debug(f"station info: {data}")
+
+ # Extract the station name (icy-name) if available
+ station_name = (
+ data.get("format", {}).get("tags", {}).get("icy-name", "Unknown Station")
+ )
+ except:
+ log.error("Could not fetch the station name")
+
+ return station_name
+
+
+# uses requests module to fetch station name [deprecated]
+def handle_station_name_from_headers(url):
+ # Get headers from URL so that we can get radio station
+ log.info("Fetching the station name")
+ log.debug("Attempting to retrieve station name from: {}".format(url))
+ station_name = "Unknown Station"
+ try:
+ # sync call, with timeout
+ response = requests.get(url, timeout=5)
+ if response.status_code == requests.codes.ok:
+ if response.headers.get("Icy-Name"):
+ station_name = response.headers.get("Icy-Name")
+ else:
+ log.error("Station name not found")
+ else:
+ log.debug("Response code received is: {}".format(response.status_code()))
+ except Exception as e:
+ # except requests.HTTPError and requests.exceptions.ReadTimeout as e:
+ log.error("Could not fetch the station name")
+ log.debug(
+ """An error occurred: {}
+ The response code was {}""".format(
+ e, e.errno
+ )
+ )
+ return station_name