From cbe8ad2b8013dfbfd507d2656578c4ed0d57e547 Mon Sep 17 00:00:00 2001 From: Dipankar Pal Date: Wed, 1 Nov 2023 23:38:03 +0530 Subject: [PATCH 01/11] feat: play random station from favorite list Signed-off-by: Dipankar Pal --- CHANGELOG.md | 5 +++++ README.md | 1 + radioactive/__main__.py | 9 +++++++++ radioactive/app.py | 2 +- radioactive/args.py | 8 ++++++++ radioactive/help.py | 5 +++++ radioactive/parser.py | 1 + radioactive/utilities.py | 9 +++++++++ 8 files changed, 39 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 59b0e36..603aab9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## 2.9.1 + +1. Play a random station from favorite list `--random` + + ## 2.9.0 1. Fetch current playing track info from runtime commands 🎶 ⚡ diff --git a/README.md b/README.md index fe8ecf2..07a4666 100644 --- a/README.md +++ b/README.md @@ -134,6 +134,7 @@ Search a station with `radio --search [STATION_NAME]` or simply `radio` :zap: to | `--filepath` | Optional | Path to save the recordings | | | `--filetype`, `-T` | Optional | Format of the recording (mp3/auto) | mp3 | | `--last` | Optional | Play last played station | False | +| `--random` | Optional | Play a random station from favorite list | 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 | diff --git a/radioactive/__main__.py b/radioactive/__main__.py index a5cc308..869cd72 100755 --- a/radioactive/__main__.py +++ b/radioactive/__main__.py @@ -22,6 +22,7 @@ handle_favorite_table, handle_listen_keypress, handle_play_last_station, + handle_play_random_station, handle_record, handle_save_last_station, handle_search_stations, @@ -193,6 +194,7 @@ def main(): and options["search_station_uuid"] is None and options["direct_play"] is None and not options["play_last_station"] + and not options["play_random"] ): ( options["curr_station_name"], @@ -239,6 +241,13 @@ def main(): ) final_step(options, last_station, alias, handler) + if options["play_random"]: + ( + options["curr_station_name"], + options["target_url"], + ) = handle_play_random_station(alias) + final_step(options, last_station, alias, handler) + if options["play_last_station"]: options["curr_station_name"], options["target_url"] = handle_play_last_station( last_station diff --git a/radioactive/app.py b/radioactive/app.py index 736a0de..60a3842 100644 --- a/radioactive/app.py +++ b/radioactive/app.py @@ -9,7 +9,7 @@ class App: def __init__(self): - self.__VERSION__ = "2.9.0" # change this on every update # + self.__VERSION__ = "2.9.1" # 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 f9af9a9..40820b4 100644 --- a/radioactive/args.py +++ b/radioactive/args.py @@ -54,6 +54,14 @@ def __init__(self): help="Play last played station.", ) + self.parser.add_argument( + "--random", + action="store_true", + default=False, + dest="play_random_station", + help="Play random station from fav list.", + ) + self.parser.add_argument( "--uuid", "-U", diff --git a/radioactive/help.py b/radioactive/help.py index ac48b8f..92b26fe 100644 --- a/radioactive/help.py +++ b/radioactive/help.py @@ -61,6 +61,11 @@ def show_help(): "Play last played station", "False", ) + table.add_row( + "--random", + "Play a random station from favorite list", + "False", + ) table.add_row( "--add , -A", diff --git a/radioactive/parser.py b/radioactive/parser.py index 00a19de..2f243ce 100644 --- a/radioactive/parser.py +++ b/radioactive/parser.py @@ -29,6 +29,7 @@ def parse_options(): options["play_last_station"] = args.play_last_station options["direct_play"] = args.direct_play + options["play_random"] = args.play_random_station options["sort_by"] = args.stations_sort_by diff --git a/radioactive/utilities.py b/radioactive/utilities.py index 8bd3e9b..0698e1c 100644 --- a/radioactive/utilities.py +++ b/radioactive/utilities.py @@ -599,3 +599,12 @@ def handle_station_name_from_headers(url): ) ) return station_name + + +def handle_play_random_station(alias): + """Select a random station from favorite menu""" + log.debug("playing a random station") + alias_map = alias.alias_map + index = randint(0, len(alias_map)) + station = alias_map[index] + return station["name"], station["uuid_or_url"] From f695a1c1762b9b4c395e35d5d5e8ce2e8e5ba7b0 Mon Sep 17 00:00:00 2001 From: Dipankar Pal Date: Sun, 5 Nov 2023 19:45:38 +0530 Subject: [PATCH 02/11] fix: :bug: duplicate favorite entry issue from runtime command fixes #100 --- radioactive/alias.py | 1 + 1 file changed, 1 insertion(+) diff --git a/radioactive/alias.py b/radioactive/alias.py index a6a63fd..8dd4b84 100644 --- a/radioactive/alias.py +++ b/radioactive/alias.py @@ -76,6 +76,7 @@ def search(self, entry): def add_entry(self, left, right): """Adds a new entry to the fav list""" + self.generate_map() if self.search(left) is not None: log.warning("An entry with same name already exists, try another name") return False From fc1b10d4c542b59784f537883063a67de2092c6c Mon Sep 17 00:00:00 2001 From: Dipankar Pal Date: Mon, 13 Nov 2023 18:40:27 +0530 Subject: [PATCH 03/11] updates --- .vscode/settings.json | 2 +- README.md | 52 +++++++++++++++++++++------------------- radioactive/__main__.py | 1 + radioactive/utilities.py | 5 +++- requirements.txt | 1 + 5 files changed, 34 insertions(+), 27 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 356a09c..f28d3f0 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -17,7 +17,7 @@ ], "files.autoSave": "off", "editor.wordWrap": "wordWrapColumn", - "workbench.colorTheme": "Quiet Light", + "workbench.colorTheme": "Default High Contrast", "editor.minimap.autohide": true, "editor.minimap.renderCharacters": false, "editor.experimentalWhitespaceRendering": "font", diff --git a/README.md b/README.md index 07a4666..74fefa1 100644 --- a/README.md +++ b/README.md @@ -120,31 +120,33 @@ Search a station with `radio --search [STATION_NAME]` or simply `radio` :zap: to ### Options -| 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 | -| `--random` | Optional | Play a random station from favorite list | 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 | +| Options | Note | Description | Default | Values | +| ------------------ | -------- | ---------------------------------------------- | ------------- | ---------------------- | +| (No Option) | Optional | Select a station from menu to play | False | | +| `--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 | `mp3`,`auto` | +| `--last` | Optional | Play last played station | False | | +| `--random` | Optional | Play a random station from favorite list | 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 | [0-100] | +| `--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 | `info`, `warning`, `error`, `debug` | +| | | | | |
diff --git a/radioactive/__main__.py b/radioactive/__main__.py index 869cd72..2e1f518 100755 --- a/radioactive/__main__.py +++ b/radioactive/__main__.py @@ -48,6 +48,7 @@ def final_step(options, last_station, alias, handler): if options["curr_station_name"].strip() == "": options["curr_station_name"] = "N/A" + # TODO: MPV,VLC support player = Player(options["target_url"], options["volume"], options["loglevel"]) handle_save_last_station( diff --git a/radioactive/utilities.py b/radioactive/utilities.py index 0698e1c..973b94c 100644 --- a/radioactive/utilities.py +++ b/radioactive/utilities.py @@ -478,7 +478,7 @@ def handle_user_choice_from_search_result(handler, response): log.debug("Asking for user input") try: - log.info("Type 'r' to play a random station") + log.info("Type 'r' to play a random station, 'f' to fuzzy find") user_input = input("Type the result ID to play: ") except EOFError: print() @@ -491,6 +491,9 @@ def handle_user_choice_from_search_result(handler, response): # pick a random integer withing range user_input = randint(1, len(response) - 1) log.debug(f"Radom station id: {user_input}") + elif user_input in ["f", "F", "fuzzy"]: + # fuzzy find all the stations, and return the selected station id + user_input = fuzzy_find(response) user_input = int(user_input) - 1 # because ID starts from 1 if user_input in range(0, len(response)): diff --git a/requirements.txt b/requirements.txt index bdad370..1ccde19 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ +setuptools requests urllib3 psutil From f036fbe842af5936dfe2acf153682ee200fc6c41 Mon Sep 17 00:00:00 2001 From: Dipankar Pal Date: Sat, 16 Dec 2023 16:09:45 +0530 Subject: [PATCH 04/11] feat: :sparkles: multiple media player support --- .vscode/settings.json | 2 +- CHANGELOG.md | 2 ++ radioactive/__main__.py | 49 +++++++++++++++++++++++----- radioactive/args.py | 9 +++++ radioactive/{player.py => ffplay.py} | 2 +- radioactive/mpv.py | 39 ++++++++++++++++++++++ radioactive/parser.py | 1 + radioactive/utilities.py | 10 +++--- radioactive/vlc.py | 39 ++++++++++++++++++++++ 9 files changed, 137 insertions(+), 16 deletions(-) rename radioactive/{player.py => ffplay.py} (99%) create mode 100644 radioactive/mpv.py create mode 100644 radioactive/vlc.py diff --git a/.vscode/settings.json b/.vscode/settings.json index f28d3f0..6d48e0f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -17,7 +17,7 @@ ], "files.autoSave": "off", "editor.wordWrap": "wordWrapColumn", - "workbench.colorTheme": "Default High Contrast", + "workbench.colorTheme": "GitHub Light High Contrast", "editor.minimap.autohide": true, "editor.minimap.renderCharacters": false, "editor.experimentalWhitespaceRendering": "font", diff --git a/CHANGELOG.md b/CHANGELOG.md index 603aab9..67d5c91 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ ## 2.9.1 1. Play a random station from favorite list `--random` +2. Mutiple media player support ( MPV, VLC, FFplay) `--player` +3. Fixed minor bugs while giving commands ## 2.9.0 diff --git a/radioactive/__main__.py b/radioactive/__main__.py index 2e1f518..e2e9bc2 100755 --- a/radioactive/__main__.py +++ b/radioactive/__main__.py @@ -12,7 +12,8 @@ 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.ffplay import Ffplay, kill_background_ffplays + from radioactive.utilities import ( check_sort_by_parameter, handle_add_station, @@ -35,21 +36,47 @@ # globally needed as signal handler needs it # to terminate main() properly -player = None +ffplay = None + + +################ + + + def final_step(options, last_station, alias, handler): - global player + + global ffplay # always needed + # check target URL for the last time if options["target_url"].strip() == "": log.error("something is wrong with the url") sys.exit(1) + if options["audio_player"] == "vlc": + from radioactive.vlc import VLC + vlc = VLC() + vlc.start(options["target_url"]) + + elif options["audio_player"] == "mpv": + from radioactive.mpv import MPV + + mpv = MPV() + mpv.start(options["target_url"]) + + elif options["audio_player"] == "ffplay": + ffplay = Ffplay(options["target_url"], options["volume"], options["loglevel"]) + + else: + log.error("Unsupported media player selected") + sys.exit(1) + + + if options["curr_station_name"].strip() == "": options["curr_station_name"] = "N/A" - # TODO: MPV,VLC support - player = Player(options["target_url"], options["volume"], options["loglevel"]) handle_save_last_station( last_station, options["curr_station_name"], options["target_url"] @@ -83,6 +110,9 @@ def final_step(options, last_station, alias, handler): loglevel=options["loglevel"], ) + ############### ffplay ################## + + def main(): log.level("info") @@ -91,7 +121,6 @@ def main(): options = parse_options() - handle_welcome_screen() VERSION = app.get_version() @@ -106,6 +135,8 @@ def main(): log.info("RADIO-ACTIVE : version {}".format(VERSION)) sys.exit(0) + handle_welcome_screen() + if options["show_help_table"]: show_help() sys.exit(0) @@ -269,11 +300,11 @@ def main(): def signal_handler(sig, frame): - global player + global ffplay log.debug("You pressed Ctrl+C!") log.debug("Stopping the radio") - if player and player.is_playing: - player.stop() + if ffplay and ffplay.is_playing: + ffplay.stop() log.info("Exiting now") sys.exit(0) diff --git a/radioactive/args.py b/radioactive/args.py index 40820b4..6aab714 100644 --- a/radioactive/args.py +++ b/radioactive/args.py @@ -219,6 +219,15 @@ def __init__(self): help="specify the audio format for recording. auto/mp3", ) + self.parser.add_argument( + "--player", + action="store", + dest="audio_player", + default="ffplay", + help="specify the audio player to use. ffplay/vlc/mpv", + ) + + def parse(self): self.result = self.parser.parse_args() if self.result is None: diff --git a/radioactive/player.py b/radioactive/ffplay.py similarity index 99% rename from radioactive/player.py rename to radioactive/ffplay.py index 82205f5..1915ff0 100644 --- a/radioactive/player.py +++ b/radioactive/ffplay.py @@ -34,7 +34,7 @@ def kill_background_ffplays(): log.info("No background radios are running!") -class Player: +class Ffplay: """FFPlayer handler, it holds all the attributes to properly execute ffplay FFmepg required to be installed separately diff --git a/radioactive/mpv.py b/radioactive/mpv.py new file mode 100644 index 0000000..931cd4d --- /dev/null +++ b/radioactive/mpv.py @@ -0,0 +1,39 @@ +# mpv player +from shutil import which +import subprocess +import sys +from zenlog import log + + +class MPV: + def __init__(self): + # check if mpv is installed + self.program_name = "mpv" + self.exe_path = which(self.program_name) + log.debug("mpv: {}".format(self.exe_path)) + + if self.exe_path is None: + log.critical("MPV not found, install it first please") + sys.exit(1) + + def start(self,url): + # call mpv with URL + self.mpv_commands = [ + self.exe_path, + url, + ] + + try: + self.process = subprocess.Popen( + self.mpv_commands, + shell=False, + stdout=subprocess.PIPE, # Capture standard output + stderr=subprocess.PIPE, # Capture standard error + text=True, # Use text mode to capture strings + ) + self.is_running = True + log.debug("player: MPV => PID {} initiated".format(self.process.pid)) + + except Exception as e: + # Handle exceptions that might occur during process setup + log.error("Error while starting radio: {}".format(e)) diff --git a/radioactive/parser.py b/radioactive/parser.py index 2f243ce..d7b7cbd 100644 --- a/radioactive/parser.py +++ b/radioactive/parser.py @@ -54,5 +54,6 @@ def parse_options(): options["target_url"] = "" options["volume"] = args.volume + options["audio_player"] = args.audio_player return options diff --git a/radioactive/utilities.py b/radioactive/utilities.py index 973b94c..23fb062 100644 --- a/radioactive/utilities.py +++ b/radioactive/utilities.py @@ -17,7 +17,7 @@ from zenlog import log from radioactive.last_station import Last_station -from radioactive.player import kill_background_ffplays +from radioactive.ffplay import kill_background_ffplays from radioactive.recorder import record_audio_auto_codec, record_audio_from_url RED_COLOR = "\033[91m" @@ -478,7 +478,7 @@ def handle_user_choice_from_search_result(handler, response): log.debug("Asking for user input") try: - log.info("Type 'r' to play a random station, 'f' to fuzzy find") + log.info("Type 'r' to play a random station") user_input = input("Type the result ID to play: ") except EOFError: print() @@ -491,9 +491,9 @@ def handle_user_choice_from_search_result(handler, response): # pick a random integer withing range user_input = randint(1, len(response) - 1) log.debug(f"Radom station id: {user_input}") - elif user_input in ["f", "F", "fuzzy"]: + #elif user_input in ["f", "F", "fuzzy"]: # fuzzy find all the stations, and return the selected station id - user_input = fuzzy_find(response) + #user_input = fuzzy_find(response) user_input = int(user_input) - 1 # because ID starts from 1 if user_input in range(0, len(response)): @@ -608,6 +608,6 @@ def handle_play_random_station(alias): """Select a random station from favorite menu""" log.debug("playing a random station") alias_map = alias.alias_map - index = randint(0, len(alias_map)) + index = randint(0, len(alias_map) -1 ) station = alias_map[index] return station["name"], station["uuid_or_url"] diff --git a/radioactive/vlc.py b/radioactive/vlc.py new file mode 100644 index 0000000..48d1482 --- /dev/null +++ b/radioactive/vlc.py @@ -0,0 +1,39 @@ +# VLC player +from shutil import which +import subprocess +import sys +from zenlog import log + + +class VLC: + def __init__(self): + # check if vlc is installed + self.program_name = "vlc" + self.exe_path = which(self.program_name) + log.debug("VLC: {}".format(self.exe_path)) + + if self.exe_path is None: + log.critical("VLC not found, install it first please") + sys.exit(1) + + def start(self,url): + # call vlc with URL + self.vlc_commands = [ + self.exe_path, + url, + ] + + try: + self.process = subprocess.Popen( + self.vlc_commands, + shell=False, + stdout=subprocess.PIPE, # Capture standard output + stderr=subprocess.PIPE, # Capture standard error + text=True, # Use text mode to capture strings + ) + self.is_running = True + log.debug("player: VLC => PID {} initiated".format(self.process.pid)) + + except Exception as e: + # Handle exceptions that might occur during process setup + log.error("Error while starting radio: {}".format(e)) From eaed09d56db9c396b74df0a996af64b47cdc22dc Mon Sep 17 00:00:00 2001 From: Dipankar Pal Date: Sat, 16 Dec 2023 16:11:25 +0530 Subject: [PATCH 05/11] fix: :bug: fails to play a single result #102 --- radioactive/utilities.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/radioactive/utilities.py b/radioactive/utilities.py index 23fb062..452aea9 100644 --- a/radioactive/utilities.py +++ b/radioactive/utilities.py @@ -465,7 +465,7 @@ def handle_user_choice_from_search_result(handler, response): print() sys.exit(0) - if user_input == ("y" or "Y"): + if user_input in ["y","Y"]: log.debug("Playing UUID from single response") global_current_station_info = response[0] From dbcea847b1646307e602871b5b50a0b784e03103 Mon Sep 17 00:00:00 2001 From: Dipankar Pal Date: Sat, 16 Dec 2023 16:16:36 +0530 Subject: [PATCH 06/11] help docs added --- README.md | 2 +- radioactive/help.py | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 74fefa1..4fa9b75 100644 --- a/README.md +++ b/README.md @@ -146,7 +146,7 @@ Search a station with `radio --search [STATION_NAME]` or simply `radio` :zap: to | `--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 | `info`, `warning`, `error`, `debug` | -| | | | | | +| `--player` | Optional | Media player to use | ffplay | `vlc`, `mpv`, `ffplay` |
diff --git a/radioactive/help.py b/radioactive/help.py index 92b26fe..6a25412 100644 --- a/radioactive/help.py +++ b/radioactive/help.py @@ -150,6 +150,12 @@ def show_help(): "info", ) + table.add_row( + "--player", + "Media player to use. vlc/mpv/ffplay", + "ffplay", + ) + console.print(table) print( "For more details : https://github.com/deep5050/radio-active/blob/main/README.md" From ce447a8c0cb062882aa3bbf04a249982ed940128 Mon Sep 17 00:00:00 2001 From: Dipankar Pal Date: Sat, 16 Dec 2023 16:17:56 +0530 Subject: [PATCH 07/11] update --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4fa9b75..b4f21d4 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ - [x] Discovers stations by genre - [x] Discovers stations by language - [ ] I'm feeling lucky! Play Random stations -- [ ] VLC, MPV player support +- [x] VLC, MPV player support > See my progress ➡️ [here](https://github.com/users/deep5050/projects/5) From 5da240a322c03f98807d45efd532c217e9a3c139 Mon Sep 17 00:00:00 2001 From: Dipankar Pal Date: Mon, 18 Dec 2023 13:26:41 +0530 Subject: [PATCH 08/11] feat: :sparkles: Defult config file support #103 --- CHANGELOG.md | 5 +-- README.md | 1 + radioactive/__main__.py | 23 +++----------- radioactive/args.py | 26 ++++++++++----- radioactive/config.py | 69 ++++++++++++++++++++++++++++++++++++++++ radioactive/mpv.py | 9 +++--- radioactive/utilities.py | 12 +++---- radioactive/vlc.py | 9 +++--- 8 files changed, 112 insertions(+), 42 deletions(-) create mode 100644 radioactive/config.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 67d5c91..9ff2d0c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,9 @@ ## 2.9.1 1. Play a random station from favorite list `--random` -2. Mutiple media player support ( MPV, VLC, FFplay) `--player` -3. Fixed minor bugs while giving commands +2. Multiple media player support ( MPV, VLC, FFplay) `--player` +3. Default config file support added +4. Fixed minor bugs while giving runtime commands ## 2.9.0 diff --git a/README.md b/README.md index b4f21d4..92a4e0c 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,7 @@ - [x] Discovers stations by language - [ ] I'm feeling lucky! Play Random stations - [x] VLC, MPV player support +- [x] Default config file > See my progress ➡️ [here](https://github.com/users/deep5050/projects/5) diff --git a/radioactive/__main__.py b/radioactive/__main__.py index e2e9bc2..c03a5e8 100755 --- a/radioactive/__main__.py +++ b/radioactive/__main__.py @@ -8,12 +8,11 @@ from radioactive.alias import Alias from radioactive.app import App +from radioactive.ffplay import Ffplay, kill_background_ffplays 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.ffplay import Ffplay, kill_background_ffplays - from radioactive.utilities import ( check_sort_by_parameter, handle_add_station, @@ -39,15 +38,8 @@ ffplay = None -################ - - - - - def final_step(options, last_station, alias, handler): - - global ffplay # always needed + global ffplay # always needed # check target URL for the last time if options["target_url"].strip() == "": @@ -56,12 +48,13 @@ def final_step(options, last_station, alias, handler): if options["audio_player"] == "vlc": from radioactive.vlc import VLC + vlc = VLC() vlc.start(options["target_url"]) elif options["audio_player"] == "mpv": from radioactive.mpv import MPV - + mpv = MPV() mpv.start(options["target_url"]) @@ -72,12 +65,9 @@ def final_step(options, last_station, alias, handler): log.error("Unsupported media player selected") sys.exit(1) - - if options["curr_station_name"].strip() == "": options["curr_station_name"] = "N/A" - handle_save_last_station( last_station, options["curr_station_name"], options["target_url"] ) @@ -110,8 +100,6 @@ def final_step(options, last_station, alias, handler): loglevel=options["loglevel"], ) - ############### ffplay ################## - def main(): @@ -121,7 +109,6 @@ def main(): options = parse_options() - VERSION = app.get_version() handler = Handler() @@ -136,7 +123,7 @@ def main(): sys.exit(0) handle_welcome_screen() - + if options["show_help_table"]: show_help() sys.exit(0) diff --git a/radioactive/args.py b/radioactive/args.py index 6aab714..f17bcfa 100644 --- a/radioactive/args.py +++ b/radioactive/args.py @@ -3,6 +3,16 @@ from zenlog import log +from radioactive.config import Configs + + +# load default configs +def load_default_configs(): + # load config file and apply configs + configs = Configs() + default_configs = configs.load() + return default_configs + class Parser: @@ -11,6 +21,7 @@ class Parser: def __init__(self): self.parser = None self.result = None + self.defaults = load_default_configs() self.parser = argparse.ArgumentParser( description="Play any radio around the globe right from the CLI ", @@ -73,7 +84,7 @@ def __init__(self): self.parser.add_argument( "--loglevel", action="store", - default="info", + default=self.defaults["loglevel"], dest="log_level", help="Specify log level", ) @@ -111,7 +122,7 @@ def __init__(self): "-L", action="store", dest="limit", - default=100, + default=self.defaults["limit"], help="Limit of entries in discover table", ) @@ -119,7 +130,7 @@ def __init__(self): "--sort", action="store", dest="stations_sort_by", - default="name", + default=self.defaults["sort"], help="Sort stations", ) @@ -169,7 +180,7 @@ def __init__(self): "-V", action="store", dest="volume", - default=80, + default=self.defaults["volume"], type=int, choices=range(0, 101, 10), help="Volume to pass down to ffplay", @@ -197,7 +208,7 @@ def __init__(self): "--filepath", action="store", dest="record_file_path", - default="", + default=self.defaults["filepath"], help="specify the audio format for recording", ) @@ -215,7 +226,7 @@ def __init__(self): "-T", action="store", dest="record_file_format", - default="mp3", + default=self.defaults["filetype"], help="specify the audio format for recording. auto/mp3", ) @@ -223,11 +234,10 @@ def __init__(self): "--player", action="store", dest="audio_player", - default="ffplay", + default=self.defaults["player"], help="specify the audio player to use. ffplay/vlc/mpv", ) - def parse(self): self.result = self.parser.parse_args() if self.result is None: diff --git a/radioactive/config.py b/radioactive/config.py new file mode 100644 index 0000000..5368be3 --- /dev/null +++ b/radioactive/config.py @@ -0,0 +1,69 @@ +# load configs from a file and apply. +# If any options are given on command line it will override the configs +import configparser +import os +import sys + +from zenlog import log + + +def write_a_sample_config_file(): + # Create a ConfigParser object + config = configparser.ConfigParser() + + # Add sections and key-value pairs + config["AppConfig"] = { + "loglevel": "info", + "limit": "100", + "sort": "votes", + "volume": "80", + "filepath": "/home/radioactive/recordings", + "filetype": "mp3", + "player": "ffplay", + } + + # Get the user's home directory + home_directory = os.path.expanduser("~") + + # Specify the file path + file_path = os.path.join(home_directory, ".radio-active-configs.ini") + + try: + # Write the configuration to the file + with open(file_path, "w") as config_file: + config.write(config_file) + + log.info(f"A sample configuration file added at: {file_path}") + + except Exception as e: + print(f"Error writing the configuration file: {e}") + + +class Configs: + def __init__(self): + self.config_path = os.path.join( + os.path.expanduser("~"), ".radio-active-configs.ini" + ) + + def load(self): + self.config = configparser.ConfigParser() + + try: + self.config.read(self.config_path) + options = {} + options["volume"] = self.config.get("AppConfig", "volume") + options["loglevel"] = self.config.get("AppConfig", "loglevel") + options["sort"] = self.config.get("AppConfig", "sort") + options["limit"] = self.config.get("AppConfig", "limit") + options["filepath"] = self.config.get("AppConfig", "filepath") + options["filetype"] = self.config.get("AppConfig", "filetype") + options["player"] = self.config.get("AppConfig", "player") + + return options + + except: + log.error("Something went wrong while parsing the config file") + # write the example config file + write_a_sample_config_file() + log.info("Rerun radioative") + sys.exit(1) diff --git a/radioactive/mpv.py b/radioactive/mpv.py index 931cd4d..c0f583b 100644 --- a/radioactive/mpv.py +++ b/radioactive/mpv.py @@ -1,7 +1,8 @@ # mpv player -from shutil import which import subprocess import sys +from shutil import which + from zenlog import log @@ -16,11 +17,11 @@ def __init__(self): log.critical("MPV not found, install it first please") sys.exit(1) - def start(self,url): + def start(self, url): # call mpv with URL self.mpv_commands = [ - self.exe_path, - url, + self.exe_path, + url, ] try: diff --git a/radioactive/utilities.py b/radioactive/utilities.py index 452aea9..b217581 100644 --- a/radioactive/utilities.py +++ b/radioactive/utilities.py @@ -16,8 +16,8 @@ from rich.text import Text from zenlog import log -from radioactive.last_station import Last_station from radioactive.ffplay import kill_background_ffplays +from radioactive.last_station import Last_station from radioactive.recorder import record_audio_auto_codec, record_audio_from_url RED_COLOR = "\033[91m" @@ -465,7 +465,7 @@ def handle_user_choice_from_search_result(handler, response): print() sys.exit(0) - if user_input in ["y","Y"]: + if user_input in ["y", "Y"]: log.debug("Playing UUID from single response") global_current_station_info = response[0] @@ -491,9 +491,9 @@ def handle_user_choice_from_search_result(handler, response): # pick a random integer withing range user_input = randint(1, len(response) - 1) log.debug(f"Radom station id: {user_input}") - #elif user_input in ["f", "F", "fuzzy"]: - # fuzzy find all the stations, and return the selected station id - #user_input = fuzzy_find(response) + # elif user_input in ["f", "F", "fuzzy"]: + # fuzzy find all the stations, and return the selected station id + # user_input = fuzzy_find(response) user_input = int(user_input) - 1 # because ID starts from 1 if user_input in range(0, len(response)): @@ -608,6 +608,6 @@ def handle_play_random_station(alias): """Select a random station from favorite menu""" log.debug("playing a random station") alias_map = alias.alias_map - index = randint(0, len(alias_map) -1 ) + index = randint(0, len(alias_map) - 1) station = alias_map[index] return station["name"], station["uuid_or_url"] diff --git a/radioactive/vlc.py b/radioactive/vlc.py index 48d1482..3c0a846 100644 --- a/radioactive/vlc.py +++ b/radioactive/vlc.py @@ -1,7 +1,8 @@ # VLC player -from shutil import which import subprocess import sys +from shutil import which + from zenlog import log @@ -16,11 +17,11 @@ def __init__(self): log.critical("VLC not found, install it first please") sys.exit(1) - def start(self,url): + def start(self, url): # call vlc with URL self.vlc_commands = [ - self.exe_path, - url, + self.exe_path, + url, ] try: From 49f517580a09a736025c04cba208076ee5db2028 Mon Sep 17 00:00:00 2001 From: Dipankar Pal Date: Mon, 18 Dec 2023 16:57:45 +0530 Subject: [PATCH 09/11] fix: :bug: Default recording filepath was ambiguas before --- README.md | 20 +++++++++++++++++++- radioactive/__main__.py | 1 - radioactive/config.py | 12 +++++++++--- radioactive/utilities.py | 4 +++- 4 files changed, 31 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 92a4e0c..57c3c8d 100644 --- a/README.md +++ b/README.md @@ -42,9 +42,9 @@ - [x] Finds nearby stations - [x] Discovers stations by genre - [x] Discovers stations by language -- [ ] I'm feeling lucky! Play Random stations - [x] VLC, MPV player support - [x] Default config file +- [ ] I'm feeling lucky! Play Random stations > See my progress ➡️ [here](https://github.com/users/deep5050/projects/5) @@ -202,6 +202,24 @@ you can sort the result page with these parameters: - `clicktrend` (currently trending stations) - `random` + +### Default configs + +Default configuration file is added into your home directory as `.radio-active-configs.ini` + +```bash +[AppConfig] +loglevel = info +limit = 100 +sort = votes +volume = 80 +filepath = /home/{user}/recordings/radioactive/ +filetype = mp3 +player = ffplay +``` + +Do NOT modify the keys, only change the values. you can give any absolute or relative path as filepath. + ### Bonus Tips 1. when using `rf`: you can force the recording to be in mp3 format by adding an extension to the file name. Example "talk-show.mp3". If you don't specify any extension it should auto-detect. Example "new_show" diff --git a/radioactive/__main__.py b/radioactive/__main__.py index c03a5e8..3ccd47d 100755 --- a/radioactive/__main__.py +++ b/radioactive/__main__.py @@ -101,7 +101,6 @@ def final_step(options, last_station, alias, handler): ) - def main(): log.level("info") diff --git a/radioactive/config.py b/radioactive/config.py index 5368be3..14201a8 100644 --- a/radioactive/config.py +++ b/radioactive/config.py @@ -1,6 +1,7 @@ # load configs from a file and apply. # If any options are given on command line it will override the configs import configparser +import getpass import os import sys @@ -17,7 +18,7 @@ def write_a_sample_config_file(): "limit": "100", "sort": "votes", "volume": "80", - "filepath": "/home/radioactive/recordings", + "filepath": "/home/{user}/recordings/radioactive/", "filetype": "mp3", "player": "ffplay", } @@ -33,7 +34,7 @@ def write_a_sample_config_file(): with open(file_path, "w") as config_file: config.write(config_file) - log.info(f"A sample configuration file added at: {file_path}") + log.info(f"A sample default configuration file added at: {file_path}") except Exception as e: print(f"Error writing the configuration file: {e}") @@ -56,6 +57,11 @@ def load(self): options["sort"] = self.config.get("AppConfig", "sort") options["limit"] = self.config.get("AppConfig", "limit") options["filepath"] = self.config.get("AppConfig", "filepath") + # if filepath has any placeholder, replace + # {user} to actual user map + options["filepath"] = options["filepath"].replace( + "{user}", getpass.getuser() + ) options["filetype"] = self.config.get("AppConfig", "filetype") options["player"] = self.config.get("AppConfig", "player") @@ -65,5 +71,5 @@ def load(self): log.error("Something went wrong while parsing the config file") # write the example config file write_a_sample_config_file() - log.info("Rerun radioative") + log.info("Re-run radioative") sys.exit(1) diff --git a/radioactive/utilities.py b/radioactive/utilities.py index b217581..1d3bf85 100644 --- a/radioactive/utilities.py +++ b/radioactive/utilities.py @@ -96,7 +96,9 @@ def handle_record( elif not record_file_path: log.debug("filepath: fallback to default path") - record_file_path = os.path.join(os.path.expanduser("~"), "Music/radioactive") + record_file_path = os.path.join( + os.path.expanduser("~"), "Music/radioactive" + ) # fallback path try: os.makedirs(record_file_path, exist_ok=True) except Exception as e: From a520f4325e1877f7cd2c6a24510b0357dbf46acf Mon Sep 17 00:00:00 2001 From: Brandon Taylor Date: Tue, 19 Dec 2023 21:16:20 -0600 Subject: [PATCH 10/11] Update config.py Tried to fix a nagging `do not use bare 'except'` error by expanding on lines 70 and 71. --- radioactive/config.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/radioactive/config.py b/radioactive/config.py index 14201a8..37cd0e2 100644 --- a/radioactive/config.py +++ b/radioactive/config.py @@ -67,9 +67,9 @@ def load(self): return options - except: - log.error("Something went wrong while parsing the config file") + except Exception as e: + log.error("Something went wrong while parsing the config file: {e}") # write the example config file write_a_sample_config_file() - log.info("Re-run radioative") + log.info("Re-run radioactive") sys.exit(1) From a23b5876d88c9abd97c696f33b53cfe1d03c75ed Mon Sep 17 00:00:00 2001 From: Brandon Taylor Date: Wed, 20 Dec 2023 06:57:41 -0600 Subject: [PATCH 11/11] Update config.py Missed a required `f` parameter at line 71 --- radioactive/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/radioactive/config.py b/radioactive/config.py index 37cd0e2..6720127 100644 --- a/radioactive/config.py +++ b/radioactive/config.py @@ -68,7 +68,7 @@ def load(self): return options except Exception as e: - log.error("Something went wrong while parsing the config file: {e}") + log.error(f"Something went wrong while parsing the config file: {e}") # write the example config file write_a_sample_config_file() log.info("Re-run radioactive")